从0到1打造企业级后端专家Agent:RAG+多模型路由+工具链+LangGraph

13 阅读10分钟

从 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


关联阅读