从 0 到 1 打造企业级后端专家 Agent:架构设计、技术选型与生产实践
今天分享一个我正在迭代的后端专家 Agent 项目:从 LangChain MVP 到 LangGraph 企业级架构,集成了 RAG 知识库、多模型路由、4 个专业工具链,覆盖 42 项自动化测试。完整开源,可直接部署使用。
一、为什么需要后端专家 Agent
通用大模型回答后端问题有两个痛点:
1. 知识陈旧,缺乏领域深度
- 通用模型知道"消息队列",但不知道"支付场景下 RocketMQ 事务消息怎么配"
- 知道"Redis 缓存",但不知道"支付中台 Redis 原子扣款 Lua 脚本怎么写"
2. 无法执行操作,只输出文字
- 让你生成 SQL 建表语句?输出了文字
- 让你画架构图?输出了文字
- 让你审查代码?输出了文字
后端专家 Agent 要解决的就是这两个问题:让 AI 有领域知识 + 让 AI 能动手干活。
二、项目整体架构
用户输入(CLI / Gradio Web)
↓
┌─────────────────────────┐
│ 1. 问题分类 │ 简单/常规/复杂 三级分类
│ (model_router.py) │ → 决定用哪个模型
└───────────┬─────────────┘
↓
┌─────────────────────────┐
│ 2. 模型路由 │ 主备降级 + 智能路由
│ (model_router.py) │ 主模型失败 → 备用模型自动切换
└───────────┬─────────────┘
↓
┌─────────────────────────┐
│ 3. RAG 检索 │ ChromaDB 领域知识库
│ (knowledge_base.py) │ Top 5 块注入 System Prompt
└───────────┬─────────────┘
↓
┌─────────────────────────┐
│ 4. LangGraph ReAct │ 自主决策:直接回答 or 调用工具
│ Agent (agent.py) │ 多轮 ReAct 循环
└───────────┬─────────────┘
↓
┌─────────────────────────┐
│ 5. 工具执行 │ 4 个专业工具
│ (tools/*.py) │ SQL / 架构图 / 代码审查 / 接口设计
└───────────┬─────────────┘
↓
┌─────────────────────────┐
│ 6. 日志持久化 │ JSONL 审计日志
│ (conversation_logger)│ 记录完整调用链路
└─────────────────────────┘
三、核心模块详解
3.1 多模型路由:智能调度 + 主备降级
为什么需要多模型路由?
问题类型分布(我观察到的):
├─ 简单问题(概念解释)→ 60%,qwen-turbo 足够
├─ 常规问题(代码片段)→ 35%,qwen-plus 性价比最高
└─ 复杂问题(架构设计)→ 5%,必须用 qwen-max
全用最强模型:成本高,响应慢
全用最弱模型:质量差,复杂问题答不对
→ 智能路由:让合适的模型处理合适的问题
路由实现:
# model_router.py
class ModelRouter:
def classify_question(self, question: str) -> str:
"""根据问题复杂度分类"""
prompt = f"""
问题:{question}
分类规则:
- 简单(SIMPLE):概念解释、定义查询、工具使用帮助
- 常规(NORMAL):代码片段、配置修改、简单调试
- 复杂(COMPLEX):架构设计、性能优化、多系统联动
输出:SIMPLE / NORMAL / COMPLEX
"""
result = self.llm.invoke(prompt).content.strip()
return result
def route(self, question: str) -> str:
"""根据分类选择模型"""
category = self.classify_question(question)
if category == "SIMPLE":
return self.fast_model # qwen-turbo
elif category == "COMPLEX":
return self.strong_model # qwen-max
else:
return self.main_model # qwen-plus
def invoke_with_fallback(self, prompt: str, question: str):
"""主备降级:主模型失败自动切换备用"""
primary = self.route(question)
try:
return self.get_model(primary).invoke(prompt)
except Exception as e:
# 主模型失败,自动降级到备用
print(f"主模型 {primary} 失败,切换到备用: {e}")
return self.get_model(self.fallback_model).invoke(prompt)
.env 配置:
# 主模型(日常主力)
OPENAI_MODEL_NAME=qwen-plus
# 备用模型(主模型失败时自动降级)
FALLBACK_MODEL=qwen-turbo
# 智能路由
SMART_ROUTING=true
# 强模型(复杂问题)
STRONG_MODEL=qwen-max
# 快速模型(简单问题)
FAST_MODEL=qwen-turbo
3.2 RAG 知识库:17 篇文档覆盖 5 大领域
为什么不用通用知识,而要自建知识库?
通用模型的知识有截止日期,且缺乏私有领域经验(公司内部规范、特定技术栈踩坑记录)。
知识库内容:
| 领域 | 篇数 | 覆盖内容 |
|---|---|---|
| 支付中台 | 6 篇 | 核心链路、风控、安全、退款、清结算、渠道接入 |
| 消息队列 | 4 篇 | 可靠投递、死信队列、幂等消费、顺序消息 |
| 架构设计 | 2 篇 | 微服务拆分、高可用部署 |
| 数据库 | 2 篇 | 分库分表、慢查询治理 |
| 性能优化 | 3 篇 | 高并发、缓存策略、限流熔断降级 |
17 篇文档 → 223 个文本块 → ChromaDB 向量存储
检索实现:
# knowledge_base.py
class KnowledgeBase:
def __init__(self, persist_dir: str = "chroma_data"):
self.collection = ChromaClient(persist_dir).get_or_create_collection(
name="backend_expert",
metadata={"description": "后端专家知识库"}
)
self.embedding = OpenAIEmbeddings()
def retrieve(self, query: str, top_k: int = 5) -> List[Dict]:
"""相似度检索 + 元数据过滤"""
results = self.collection.query(
query_texts=[query],
n_results=top_k
)
# 拼接为上下文
context_parts = []
for i, doc in enumerate(results["documents"][0]):
metadata = results["metadatas"][0][i]
context_parts.append(
f"[{metadata['domain']}] {metadata['title']}\n{doc}"
)
return "\n\n---\n\n".join(context_parts)
def add_document(self, text: str, metadata: Dict):
"""添加新文档到知识库"""
chunks = self.chunk_text(text) # 文本分块
self.collection.add(
documents=chunks,
metadatas=[metadata] * len(chunks),
ids=[f"chunk_{i}" for i in range(len(chunks))]
)
3.3 工具链:让 AI 能动手干活
通用 Agent 只输出文字,我们的 Agent 能生成 SQL、画架构图、审查代码。
工具框架设计:
# tools/base.py
class BaseTool:
"""工具基类,所有工具继承此框架"""
name: str # 工具名称
description: str # 工具描述(AI 根据此决定是否调用)
parameters: dict # JSON Schema 参数定义
def execute(self, **kwargs) -> str:
"""工具执行逻辑,子类必须实现"""
raise NotImplementedError
class ToolRegistry:
"""工具注册中心,AI 根据描述自动匹配工具"""
def __init__(self):
self.tools: Dict[str, BaseTool] = {}
def register(self, tool: BaseTool):
self.tools[tool.name] = tool
def get_tool(self, name: str) -> BaseTool:
return self.tools.get(name)
def get_all_descriptions(self) -> str:
"""生成工具描述,供 AI 参考"""
return "\n".join([
f"- {t.name}: {t.description}"
for t in self.tools.values()
])
4 个专业工具:
工具 1:SQL 生成器
# tools/sql_generator.py
class SqlGeneratorTool(BaseTool):
name = "sql_generator"
description = "根据需求生成 MySQL DDL 建表语句或 DML 查询语句"
parameters = {
"type": "object",
"properties": {
"task": {"type": "string", "description": "任务类型:create_table / query"},
"requirements": {"type": "string", "description": "业务需求描述"}
},
"required": ["task", "requirements"]
}
def execute(self, task: str, requirements: str) -> str:
if task == "create_table":
return self.generate_ddl(requirements)
elif task == "query":
return self.generate_dml(requirements)
return "不支持的任务类型"
def generate_ddl(self, requirements: str) -> str:
"""生成建表语句,包含索引、分区建议"""
prompt = f"""
请为以下需求生成 MySQL 建表语句:
{requirements}
要求:
1. 字段命名遵循小写下划线
2. 必须包含 created_at、updated_at 字段
3. 必须包含主键和必要的索引
4. 附上分表策略建议(如需)
"""
return llm.invoke(prompt).content
工具 2:架构绘图
# tools/architecture_diagram.py
class ArchitectureDiagramTool(BaseTool):
name = "architecture_diagram"
description = "生成 Mermaid 格式的架构图、时序图、流程图、ER图"
parameters = {
"type": "object",
"properties": {
"diagram_type": {"type": "string", "enum": ["topology", "sequence", "flowchart", "er"]},
"content": {"type": "string", "description": "架构/业务描述"}
}
}
def execute(self, diagram_type: str, content: str) -> str:
if diagram_type == "topology":
return self.generate_topology(content)
elif diagram_type == "sequence":
return self.generate_sequence(content)
elif diagram_type == "flowchart":
return self.generate_flowchart(content)
elif diagram_type == "er":
return self.generate_er(content)
return "不支持的图类型"
工具 3:代码审查
# tools/code_review.py
class CodeReviewTool(BaseTool):
name = "code_review"
description = "审查 Java/Spring Boot 代码,给出改进建议"
parameters = {
"type": "object",
"properties": {
"language": {"type": "string", "default": "java"},
"code": {"type": "string", "description": "待审查代码"},
"focus": {"type": "string", "description": "审查重点:性能/安全/规范/全部"}
}
}
def execute(self, language: str, code: str, focus: str = "全部") -> str:
prompt = f"""
请审查以下 {language} 代码,重点关注:{focus}
审查维度:
1. 安全性:SQL注入、XSS、敏感信息暴露
2. 性能:N+1查询、全表扫描、循环内查库
3. 规范:命名、异常处理、资源关闭
4. 可维护性:耦合度、复杂度、方法长度
代码:
```{language}
{code}
```
输出格式:
| 维度 | 问题 | 位置 | 建议 |
|------|------|------|------|
"""
return llm.invoke(prompt).content
工具 4:接口设计
# tools/api_design.py
class ApiDesignTool(BaseTool):
name = "api_design"
description = "设计 RESTful API 接口规范"
parameters = {
"type": "object",
"properties": {
"service": {"type": "string", "description": "服务名称"},
"requirements": {"type": "string", "description": "业务需求"}
}
}
def execute(self, service: str, requirements: str) -> str:
prompt = f"""
请为 {service} 服务设计 RESTful API 接口:
业务需求:{requirements}
输出格式:
1. 路由设计(HTTP方法 + 路径)
2. 请求参数(Query/Path/Body)
3. 响应格式(成功 + 失败)
4. 错误码规范
"""
return llm.invoke(prompt).content
3.4 LangGraph ReAct Agent:让 AI 自主决策
为什么从 LangChain Agents 迁移到 LangGraph?
LangChain Agents 是链式调用,无法回溯;LangGraph 是状态图,可以循环、多步推理、记忆。
# agent.py
from langgraph.graph import StateGraph, END
from typing import TypedDict
class AgentState(TypedDict):
question: str
context: str
model: str
response: str
tool_calls: List[Dict]
iteration: int
def build_agent() -> StateGraph:
workflow = StateGraph(AgentState)
# 节点
workflow.add_node("classify", classify_node) # 问题分类
workflow.add_node("retrieve", retrieve_node) # RAG 检索
workflow.add_node("reason", reason_node) # LLM 推理
workflow.add_node("execute_tool", execute_tool_node) # 执行工具
# 边
workflow.set_entry_point("classify")
workflow.add_edge("classify", "retrieve")
workflow.add_edge("retrieve", "reason")
# 条件边:推理决定是否调用工具
workflow.add_conditional_edges(
"reason",
should_use_tools,
{
"tool": "execute_tool",
"end": END
}
)
workflow.add_edge("execute_tool", "reason") # 工具执行后继续推理
return workflow.compile()
def should_use_tools(state: AgentState) -> str:
"""ReAct 判断:是否需要调用工具"""
last_response = state["response"]
# 简单判断:响应中包含工具调用指令
if "TOOL_CALL:" in last_response or "[TOOL]" in last_response:
return "tool"
return "end"
3.5 对话日志:生产环境审计不可少
# conversation_logger.py
class ConversationLogger:
"""JSONL 格式持久化,每次对话一条记录"""
def log(self, conversation: ConversationRecord):
log_file = Path("logs/conversations.jsonl")
with open(log_file, "a", encoding="utf-8") as f:
f.write(conversation.model_dump_json() + "\n")
def query_stats(self) -> Dict:
"""统计分析"""
total = 0
tool_usage = Counter()
model_usage = Counter()
for line in open("logs/conversations.jsonl"):
record = json.loads(line)
total += 1
tool_usage.update(record.get("tools_used", []))
model_usage.update([record.get("model", "unknown")])
return {
"total_conversations": total,
"tool_usage": dict(tool_usage),
"model_usage": dict(model_usage)
}
日志记录内容:
{
"timestamp": "2026-04-20T11:30:00",
"question": "如何设计支付订单的分库分表?",
"model": "qwen-plus",
"response_length": 2500,
"tools_used": ["sql_generator"],
"rag_chunks_retrieved": 5,
"latency_ms": 3200,
"iteration_count": 2
}
四、评估体系:4 维度量化 Agent 质量
# evaluator.py
class AgentEvaluator:
"""4 维度自动化评估"""
dimensions = ["relevance", "completeness", "tool_usage", "quality"]
def evaluate(self, question: str, expected: str, actual: str) -> Dict:
return {
"relevance": self.score_relevance(question, actual),
"completeness": self.score_completeness(expected, actual),
"tool_usage": self.score_tool_usage(question, actual),
"quality": self.score_quality(actual)
}
def run_benchmark(self, test_cases: List[TestCase]) -> pd.DataFrame:
"""运行测试集,输出评估报告"""
results = []
for case in test_cases:
actual = self.agent.ask(case.question)
scores = self.evaluate(case.question, case.expected, actual)
results.append({"case": case.name, **scores})
return pd.DataFrame(results)
预置 10 个测试用例,覆盖 5 大领域 + 工具调用:
| 测试用例 | 领域 | 评估重点 |
|---|---|---|
| 支付订单表设计 | 数据库 | SQL 正确性 |
| RocketMQ 事务消息 | 消息队列 | 知识准确性 |
| Redis 分布式锁 | 缓存 | 实现完整性 |
| Spring Boot 启动优化 | 性能 | 可操作性 |
| 微服务拆分原则 | 架构 | 回答相关性 |
| SQL 生成工具 | 工具 | 工具调用 |
| 架构图生成 | 工具 | Mermaid 语法 |
| 代码审查 | 工具 | 审查维度 |
| 接口设计 | 工具 | RESTful 规范 |
| 综合问答 | 全领域 | 综合质量 |
五、Docker 一键部署
# 1. 克隆项目
git clone <repo-url>
cd backend-expert-agent
# 2. 配置 API Key
cp .env.example .env
# 编辑 .env,填入阿里云百炼 API Key
# 3. 一键启动
docker compose up -d
# 4. 访问
# http://localhost:7860
docker-compose.yml:
services:
backend-agent:
build: .
ports:
- "7860:7860"
volumes:
- ./.env:/app/.env
- ./logs:/app/logs
- ./chroma_data:/app/chroma_data
environment:
- PYTHONUNBUFFERED=1
restart: unless-stopped
六、迭代路线图与踩坑总结
迭代 1(MVP):LangChain Agent + ChromaDB RAG
迭代 2(工具):BaseTool 框架 + 4 个专业工具 + LangGraph
迭代 3(企业级):Gradio Web + 多模型路由 + 评估体系 + Docker
核心踩坑:
| 坑 | 解决方案 |
|---|---|
| LangChain Agents 无法回溯 | 迁移到 LangGraph 状态图 |
| ChromaDB 中文分词效果差 | 增大 chunk_size + overlap |
| 工具调用描述不够清晰 | 用 JSON Schema + Few-shot 示例 |
| 模型响应不稳定 | 主备降级 + 重试机制 |
| Web 界面中文乱码 | Gradio 指定 server_name="0.0.0.0" + UTF-8 |
七、总结
这个项目解决的核心问题:让 AI 成为真正的后端专家助手,而不是只会说"建议"的客服。
关键特性:
- RAG 知识库:17 篇文档覆盖支付、MQ、数据库、架构、性能 5 大领域
- 4 个专业工具:SQL 生成、架构绘图、代码审查、接口设计
- 多模型路由:成本与质量的平衡,智能选模型
- LangGraph:支持多轮推理、工具调用循环
- 评估体系:4 维度量化,每次迭代有数据支撑
- 42 项测试:全量自动化回归,发布有信心
Gitee 地址:backend-expert-agent
关联阅读: