智旅云图(一个智能旅游规划项目)学习指南

🗺️ 智旅云图后端学习指南

本文档从 0 开始讲解如何阅读和理解这个 AI 旅行规划项目的后端代码。


1. 项目概览

1.1 项目定位

智旅云图是一个面向中文旅行场景的 AI 旅行规划系统,核心价值在于:

  • 🧠 LLM 行程生成 :基于 LangChain + DashScope 调用 qwen-max 生成结构化旅行计划
  • 📚 RAG 攻略增强:本地 Markdown 攻略 + Chroma 向量检索,为生成结果补充目的地上下文
  • 🗺️ 高德地图接入:补充景点地址、经纬度、POI ID、路线距离、耗时和景点图片
  • 🌦️ 天气感知提示:前端展示天气预报,并根据雨天/阴天自动修正旅行提示
  • Redis 缓存层:覆盖天气、地图、RAG 检索与 Rerank 结果缓存
  • 📄 文档导出:支持 Markdown 和中文 PDF 导出

1.2 技术栈

层级 技术 版本
Web框架 FastAPI >=0.110
数据验证 Pydantic >=2.6
ORM SQLAlchemy >=2.0
LLM框架 LangChain >=0.2
向量库 ChromaDB >=0.5
缓存 Redis >=5.0
HTTP客户端 HTTPX >=0.27
PDF生成 ReportLab >=4.0

1.3 目录结构

text 复制代码
backend/
├── app/                    # 核心应用代码
│   ├── config.py           # 环境变量配置、数据库连接
│   ├── api/                # 接口路由层
│   │   ├── main.py         # FastAPI 入口
│   │   └── routes/         # trip/export/weather 路由
│   ├── services/           # 业务服务层
│   │   ├── trip_service.py     # 行程主编排逻辑
│   │   ├── cache_service.py    # Redis缓存封装
│   │   ├── map_service.py      # 高德地图服务
│   │   ├── weather_service.py  # 天气服务
│   │   ├── storage_service.py  # SQLite持久化
│   │   └── export_service.py   # 文档导出
│   ├── agents/             # LLM Agent层
│   │   ├── trip_planner_agent.py  # 行程生成Agent
│   │   └── tools/
│   │       └── rag_tool.py         # Query Rewrite工具
│   ├── rag/                # RAG检索层
│   │   ├── vector_db.py    # Chroma入库与检索
│   │   └── retriever.py    # 检索封装与Rerank
│   └── models/             # 数据模型
│       ├── schemas.py      # Pydantic请求/响应模型
│       └── db_models.py    # SQLAlchemy数据库模型
├── data/                   # 本地攻略文档
├── scripts/                # 辅助脚本(ingest/测试)
├── tests/                  # pytest测试
├── .env.example            # 环境变量模板
└── requirements.txt        # 依赖清单

2. 核心配置与环境

2.1 配置文件 (app/config.py)

这是项目的配置中心,负责:

  1. 数据库配置

    • SQLite 数据库路径:backend/db/app.db
    • SQLAlchemy Engine 和 Session 配置
  2. LLM 配置(通过环境变量注入)

    • LLM_API_KEY:DashScope API Key
    • LLM_MODEL:模型名称(如 qwen-max
    • LLM_BASE_URL:API 端点(DashScope 兼容 OpenAI)
    • LLM_TIMEOUT_SECONDS:超时时间
    • LLM_MAX_RETRIES:重试次数
  3. RAG 配置

    • CHROMA_DB_DIR:Chroma 向量库持久化目录
    • CHROMA_COLLECTION_NAME:集合名称
    • EMBEDDING_MODEL:嵌入模型(如 text-embedding-v4
    • RERANK_MODEL:重排序模型(如 qwen3-rerank
  4. Redis 配置

    • REDIS_ENABLED:是否开启缓存
    • REDIS_URL:Redis 连接地址
    • 各类型缓存的 TTL 设置(天气/地图/RAG/Rerank)
  5. 高德地图配置

    • AMAP_API_KEY:高德 Web 服务 Key
    • ENABLE_AMAP_ENRICHMENT:是否开启地图信息补全

2.2 环境变量模板 (.env.example)

env 复制代码
# LLM
LLM_PROVIDER=openai_compatible
LLM_API_KEY=your_dashscope_api_key
LLM_MODEL=qwen-max
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_TIMEOUT_SECONDS=60
LLM_MAX_RETRIES=1

# RAG
CHROMA_DB_DIR=db/chroma_db
CHROMA_COLLECTION_NAME=travel_guides
EMBEDDING_MODEL=text-embedding-v4
RERANK_MODEL=qwen3-rerank

# Redis
REDIS_ENABLED=false
REDIS_URL=redis://127.0.0.1:6379/0
REDIS_KEY_PREFIX=trip_planner

# 高德地图
AMAP_API_KEY=your_amap_web_service_key
ENABLE_AMAP_ENRICHMENT=true

3. 数据模型

3.1 Pydantic Schemas (app/models/schemas.py)

核心模型关系
复制代码
TripRequest(请求)→ Itinerary(行程)→ DayPlan(单日)→ SpotItem/MealItem/HotelItem/TransportItem
关键模型解析

TripRequest - 用户行程生成请求:

python 复制代码
class TripRequest(BaseModel):
    destination: str          # 目的地
    start_date: DateType      # 出发日期
    end_date: DateType        # 结束日期
    travelers: int            # 人数
    budget: float             # 预算
    preferences: list[str]    # 偏好标签(美食/亲子/自然等)
    pace: str | None          # 节奏(轻松/适中/紧凑)
    dietary_preferences: list[str]  # 饮食偏好
    hotel_level: str | None   # 酒店档次
    special_notes: str | None # 额外要求(如"想看日落")

Itinerary - 完整行程数据结构:

python 复制代码
class Itinerary(BaseModel):
    trip_id: str              # 行程唯一标识
    destination: str          # 目的地
    summary: str              # 行程概述
    days: list[DayPlan]       # 逐日行程
    estimated_budget: float   # 总预算
    budget_breakdown: BudgetBreakdown  # 预算拆分
    tips: list[str]           # 旅行提示
    source_notes: list[str]   # RAG来源说明

DayPlan - 单日行程:

python 复制代码
class DayPlan(BaseModel):
    day_index: int            # 第几天(从1开始)
    date: DateType | None     # 日期
    theme: str | None         # 当天主题
    spots: list[SpotItem]     # 景点安排
    meals: list[MealItem]     # 餐饮安排
    hotel: HotelItem | None   # 住宿安排
    transport: list[TransportItem]  # 交通安排
    notes: list[str]          # 备注

BudgetBreakdown - 预算拆分:

python 复制代码
class BudgetBreakdown(BaseModel):
    transport: float  # 交通
    hotel: float      # 住宿
    meals: float      # 餐饮
    tickets: float    # 门票
    other: float      # 其他
    total: float      # 总计

3.2 SQLAlchemy Models (app/models/db_models.py)

TripRecord - 数据库表模型:

python 复制代码
class TripRecord(Base):
    __tablename__ = "trip_records"
    
    id: Mapped[int] = mapped_column(primary_key=True)
    trip_id: Mapped[str] = mapped_column(String(100), unique=True, index=True)
    destination: Mapped[str]
    summary: Mapped[str]
    itinerary_json: Mapped[str]  # 完整行程的JSON字符串
    created_at: Mapped[datetime]
    updated_at: Mapped[datetime]

设计要点:使用 JSON 字符串存储完整行程,便于灵活扩展而无需修改表结构。


4. 接口层(API Routes)

4.1 入口文件 (app/api/main.py)

python 复制代码
app = FastAPI(
    title="Trip Planner Demo Backend",
    description="MVP backend for the intelligent travel assistant.",
    version="0.1.0",
)

# CORS 跨域配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 注册路由
app.include_router(trip_router)
app.include_router(export_router)
app.include_router(weather_router)

4.2 Trip 路由 (app/api/routes/trip.py)

方法 路径 功能 响应模型
POST /trip/generate 生成行程 Itinerary
POST /trip/edit 智能编辑 Itinerary
POST /trip/save 保存行程 {"message", "trip_id"}
GET /trip 历史列表 TripListResponse
GET /trip/{trip_id} 行程详情 TripDetailResponse
DELETE /trip/{trip_id} 删除行程 {"message", "trip_id"}

核心代码示例

python 复制代码
@router.post("/generate", response_model=Itinerary)
def generate_trip(request: TripRequest) -> Itinerary:
    """生成结构化 itinerary。"""
    return generate_trip_itinerary(request)

5. 服务层(Services)

5.1 Trip Service (app/services/trip_service.py) - 核心编排

这是最核心的业务编排层,负责:

  1. 行程生成主流程 (generate_trip_itinerary)
  2. 智能编辑流程 (edit_trip_itinerary)
  3. 预算计算
  4. 地图信息补全
行程生成流程
scss 复制代码
用户请求 → collect_trip_context(RAG检索) → generate_planner_draft(LLM生成)
    ↓
预算拆分计算 → _maybe_enrich_itinerary_with_map_data(地图补全) → 返回Itinerary

关键代码解析

python 复制代码
def generate_trip_itinerary(request: TripRequest) -> Itinerary:
    # 1. 计算天数
    day_count = (request.end_date - request.start_date).days + 1
    
    # 2. RAG检索获取攻略上下文
    rag_contexts = collect_trip_context(
        destination=request.destination,
        preferences=request.preferences,
        pace=request.pace,
        special_notes=request.special_notes,
    )
    
    # 3. LLM生成结构化草稿
    llm_draft = generate_planner_draft(request, rag_contexts, day_count)
    
    # 4. 构建每日行程
    days = []
    for index in range(day_count):
        # 根据LLM结果或规则构建DayPlan
        ...
    
    # 5. 地图信息补全(可选)
    return _maybe_enrich_itinerary_with_map_data(itinerary, city=request.destination)
预算计算机制

项目实现了智能预算拆分,考虑多种因素:

  1. 酒店档次权重:豪华(0.62) > 高档(0.56) > 舒适(0.50) > 经济(0.40)
  2. 美食偏好加成:有"美食"偏好时餐饮预算增加12%
  3. 节奏影响:紧凑节奏交通预算更高,轻松节奏更低
  4. 周末溢价:周五、周六住宿费用增加18%
  5. 首尾日加成:首尾日交通预算增加
python 复制代码
def _estimate_ticket_cost(spot_name: str, description: str | None) -> float:
    """根据景点关键词估算门票"""
    text = f"{spot_name} {description or ''}"
    
    if any(keyword in text for keyword in ("古城", "古镇", "公园")):
        return [0.0, 20.0, 30.0, 40.0][bucket]  # 低收费或免费
    if any(keyword in text for keyword in ("寺", "博物馆", "遗址")):
        return round(60.0 + (bucket * 18.0), 2)  # 中等收费
    if any(keyword in text for keyword in ("索道", "缆车", "游船")):
        return round(120.0 + (bucket * 28.0), 2)  # 高收费

5.2 Cache Service (app/services/cache_service.py)

设计亮点

  1. 懒加载:Redis 客户端按需初始化
  2. 优雅降级:Redis 不可用时自动跳过缓存,不影响主流程
  3. 统一 Key 前缀:避免多项目缓存键冲突
  4. JSON 序列化:自动处理复杂数据类型的缓存
python 复制代码
def _get_redis_client():
    """懒加载 Redis 客户端;不可用时返回 None"""
    global _redis_client
    
    if not REDIS_ENABLED:
        return None
    if redis is None:
        logger.warning("Redis 依赖未安装,缓存功能跳过")
        return None
    if _redis_client is not None:
        return _redis_client
    
    # 尝试连接
    try:
        client = redis.Redis.from_url(REDIS_URL, decode_responses=True)
        client.ping()
        _redis_client = client
        return _redis_client
    except Exception as exc:
        logger.warning("Redis 连接失败:%s", exc)
        return None

缓存类型与 TTL

缓存类型 TTL 说明
天气 30分钟 天气变化较慢
地图 24小时 POI信息相对稳定
RAG检索 6小时 攻略内容不变但query可能变化
Rerank结果 6小时 相同query+候选集结果稳定

5.3 Map Service (app/services/map_service.py)

对接高德地图 Web 服务,提供:

  1. 地理编码 (geocode_address):地址 → 经纬度
  2. POI搜索 (search_places):关键词 → 景点信息(含图片)
  3. 路线估算 (estimate_route):两点 → 距离/耗时/打车费用
python 复制代码
def enrich_itinerary_with_map_data(itinerary: Itinerary, city: str | None = None) -> Itinerary:
    """补全 itinerary 中的地图字段"""
    for day in itinerary.days:
        for spot in day.spots:
            _enrich_spot(spot, city=city)  # 补充地址、坐标、POI ID、图片
        
        if day.hotel is not None:
            _enrich_hotel(day.hotel, city=city)
        
        for transport in day.transport:
            _enrich_transport(transport, city=city)  # 补充路线距离和耗时
    
    return itinerary

5.4 Weather Service (app/services/weather_service.py)

通过高德天气 API 获取未来天气预报,支持缓存。

python 复制代码
def get_weather_forecast(city: str) -> dict[str, Any]:
    """获取指定城市的未来天气预报"""
    cache_key = f"weather:forecast:{city.lower()}"
    cached_value = get_cached_json(cache_key)
    if cached_value is not None:
        return cached_value
    
    # 先地理编码获取城市编码
    geocode = geocode_address(city, city=city)
    city_code = geocode.get("adcode") if geocode else city
    
    # 调用高德天气API
    payload = _request_amap_weather("/weather/weatherInfo", {"city": city_code, "extensions": "all"})
    ...

5.5 Storage Service (app/services/storage_service.py)

SQLite 持久化操作:

函数 功能
save_itinerary 保存/更新行程
get_itinerary_by_trip_id 查询单个行程
list_saved_itineraries 获取历史列表
delete_itinerary_by_trip_id 删除行程
python 复制代码
def save_itinerary(itinerary: Itinerary) -> str:
    init_db()  # 自动创建表
    
    session = SessionLocal()
    try:
        itinerary_json = json.dumps(itinerary.model_dump(mode="json"), ensure_ascii=False)
        
        # 存在则更新,不存在则新建
        existing_record = session.query(TripRecord).filter(
            TripRecord.trip_id == itinerary.trip_id
        ).first()
        
        if existing_record is None:
            record = TripRecord(...)
            session.add(record)
        else:
            existing_record.summary = itinerary.summary
            existing_record.itinerary_json = itinerary_json
        
        session.commit()
        return itinerary.trip_id
    finally:
        session.close()

5.6 Export Service (app/services/export_service.py)

支持两种导出格式:

  1. Markdown:轻量级,便于分享
  2. PDF:结构化排版,适合打印
python 复制代码
def itinerary_to_markdown(trip_detail: TripDetailResponse) -> str:
    """渲染成 Markdown"""
    lines = [
        f"# {itinerary.destination} 行程单",
        f"- 目的地:{itinerary.destination}",
        f"- 预计预算:{itinerary.estimated_budget:.2f} 元",
        "## 行程概述",
        itinerary.summary,
        "## 每日安排",
        ...
    ]
    return "\n".join(lines)

def itinerary_to_pdf_bytes(trip_detail: TripDetailResponse) -> bytes:
    """渲染成 PDF 二进制内容"""
    from reportlab.platypus import SimpleDocTemplate, Paragraph, Table
    ...

6. Agent 层(LLM 调用)

6.1 Trip Planner Agent (app/agents/trip_planner_agent.py)

负责结构化行程生成单日编辑

核心数据结构
python 复制代码
class PlannerDraft(BaseModel):
    """LLM 返回的结构化行程草稿"""
    summary: str              # 整体概述
    tips: list[str]           # 旅行提示
    days: list[PlannerDayDraft]  # 每日草稿

class PlannerDayDraft(BaseModel):
    """单日草稿"""
    day_index: int            # 第几天
    theme: str               # 当天主题
    spot_name: str           # 主要景点
    spot_description: str    # 景点说明
    meal_name: str           # 餐饮建议
    meal_notes: str          # 餐饮说明
    daily_note: str          # 当天备注
生成流程
python 复制代码
def generate_planner_draft(request: TripRequest, rag_contexts: list[str], day_count: int) -> PlannerDraft | None:
    # 1. 创建 LLM 客户端
    llm = _build_chat_llm()
    if llm is None:
        return None  # 优雅降级
    
    # 2. 构建 Prompt
    system_prompt = "你是一名旅行规划助手。请用中文生成简洁的结构化旅行草稿..."
    human_prompt = f"""
    目的地:{request.destination}
    天数:{day_count}
    预算:{request.budget}
    本地攻略上下文:
    {rag_contexts}
    ...
    """
    
    # 3. 调用 LLM
    response = llm.invoke([("system", system_prompt), ("human", human_prompt)])
    
    # 4. 解析 JSON 输出
    json_text = _extract_json_object(str(response.content))
    result = PlannerDraft.model_validate(json.loads(json_text))
    
    return result

关键设计

  1. 结构化输出要求:强制 LLM 返回 JSON 格式,便于程序解析
  2. 优雅降级:LLM 不可用时返回 None,服务层回退到规则实现
  3. 用户诉求落实:如"想看日落"必须在具体某天的安排中体现

6.2 RAG Tool (app/agents/tools/rag_tool.py)

负责Query Rewrite - 将用户的旅行需求转换成适合向量检索的查询词:

双重策略
  1. LLM-based Rewrite(优先):用 qwen-max 将自然语言需求转换成检索关键词
  2. Rule-based Rewrite(fallback):基于规则提取关键词
python 复制代码
def build_destination_query(destination: str, preferences: list[str] | None, 
                            pace: str | None, special_notes: str | None) -> str:
    # 优先 LLM 改写
    llm_query = llm_rewrite_query(destination, preferences, pace, special_notes)
    if llm_query:
        return llm_query
    
    # Fallback 到规则级
    return _rule_based_query(destination, preferences, pace, special_notes)

规则级关键词提取示例

python 复制代码
rule_keywords = [
    (("日落", "傍晚"), "大理", ["日落", "傍晚", "洱海", "双廊"]),
    (("日出", "清晨"), "大理", ["日出", "才村", "龙龛"]),
    (("拍照", "出片"), None, ["拍照", "摄影", "出片"]),
    (("美食", "小吃"), None, ["美食", "小吃"]),
    (("骑行",), "大理", ["骑行", "洱海生态廊道"]),
    (("熊猫",), "成都", ["大熊猫", "熊猫"]),
]

7. RAG 层(检索增强)

7.1 Vector DB (app/rag/vector_db.py)

负责离线数据入库在线向量检索

离线流程
scss 复制代码
本地攻略(.md) → _split_markdown_into_chunks(按标题切分) → _build_embeddings(生成向量) → ChromaDB
python 复制代码
def ingest_guide_chunks_to_chroma() -> int:
    """把本地攻略片段写入 Chroma"""
    embeddings = _build_embeddings()
    collection = _get_chroma_collection()
    chunks = load_guide_chunks()  # 读取并切分 Markdown
    
    documents = [_build_document_text(chunk) for chunk in chunks]
    vectors = embeddings.embed_documents(documents)
    
    collection.upsert(
        ids=[chunk["id"] for chunk in chunks],
        documents=documents,
        metadatas=[{"title": chunk["title"], "source": chunk["source"]} for chunk in chunks],
        embeddings=vectors,
    )
    return len(chunks)
在线检索
python 复制代码
def search_guide_chunks(query: str, top_k: int = 3) -> list[dict[str, str]]:
    """优先向量检索,fallback关键词匹配"""
    chroma_results = _search_guide_chunks_by_chroma(query, top_k)
    if chroma_results:
        return chroma_results
    return _search_guide_chunks_by_keywords(query, top_k)  # 降级方案

7.2 Retriever (app/rag/retriever.py)

负责检索结果重排序缓存管理

Rerank 策略
  1. Cross-encoder Rerank(优先):调用 qwen3-rerank 做语义重排序
  2. Rule-based Rerank(fallback):基于关键词匹配打分
python 复制代码
def rerank_guide_chunks(query: str, matched_chunks: list[dict[str, str]], 
                        top_k: int, destination: str | None = None) -> list[dict[str, str]]:
    # 先查缓存
    cache_key = _build_rerank_cache_key(query, matched_chunks)
    cached = get_cached_json(cache_key)
    if cached is not None:
        return cached
    
    # 优先 Cross-encoder
    dashscope_results = _rerank_with_dashscope(query, matched_chunks, top_k)
    if dashscope_results:
        set_cached_json(cache_key, results, expire_seconds=REDIS_RERANK_TTL_SECONDS)
        return results
    
    # Fallback 规则级
    return _rule_based_rerank(query, matched_chunks, top_k, destination)

规则级打分逻辑

条件 分数调整 说明
关键词在标题中 +3 标题匹配权重更高
关键词在正文中 +1 正文匹配权重较低
"文档开头"噪声 -8 文档开头信息量低
"行程"标题 +4 行程类片段更相关
"行程参考"标题 -4 过于泛化,降权
目的地不匹配 -5 跨目的地污染降权

8. 核心业务流程

8.1 行程生成流程

arduino 复制代码
POST /trip/generate
    ↓
trip.py(路由层)
    ↓
trip_service.py(主编排)
    ↓
① rag_tool.py → Query Rewrite(LLM-based / 规则 fallback)
    ↓
   retriever.py → RAG缓存检查 → ChromaDB向量召回 → 噪声预过滤 → Cross-encoder Rerank
    ↓
② trip_planner_agent.py → 组装Prompt → qwen-max生成 → Pydantic校验
    ↓
③ map_service.py(逐景点)→ 地理编码 → POI搜索 → 路线估算 → 图片补充
    ↓
④ weather_service.py → 天气预报查询(可选)
    ↓
⑤ 预算拆分计算
    ↓
返回 Itinerary

8.2 智能编辑流程

bash 复制代码
POST /trip/edit
    ↓
trip.py(路由层)
    ↓
trip_service.py(主编排)
    ↓
① 定位目标 DayPlan(解析 edit_scope)
    ↓
② trip_planner_agent.py → generate_day_edit_draft(LLM编辑)
    ↓
   失败则 fallback 到规则编辑(关键词匹配)
    ↓
③ 替换目标 DayPlan 的 theme/spots/meals/notes
    ↓
④ map_service.py 重新 enrich(清除旧坐标,重新查询)
    ↓
⑤ 更新 tips 和 source_notes
    ↓
返回更新后的 Itinerary

8.3 保存与导出流程

bash 复制代码
POST /trip/save → storage_service.py → SQLite 持久化

GET /export/{trip_id}/markdown
    ↓
storage_service.py 读取 itinerary
    ↓
export_service.py → Jinja2 渲染 Markdown

GET /export/{trip_id}/pdf
    ↓
storage_service.py 读取 itinerary
    ↓
export_service.py → ReportLab 生成中文 PDF
    ↓
Content-Disposition 返回下载文件名

9. 辅助脚本

9.1 数据入库 (scripts/ingest_data.py)

首次使用前执行,将本地攻略文档写入 ChromaDB:

bash 复制代码
cd backend
python scripts/ingest_data.py

9.2 RAG 调试 (scripts/debug_rag_retrieval.py)

调试检索效果,输出:

  • 检索 query
  • top-k 召回片段
  • rerank_score 与 rerank_reasons

9.3 RAG 评估 (scripts/evaluate_rag_retrieval.py)

量化评估检索效果:

  • Top1/TopK 命中率
  • MRR(平均倒数排名)
  • Noise Rate(噪声率)
  • Latency(延迟)
  • Cross-destination Pollution(跨目的地污染)

10. 测试与验证

10.1 运行测试

bash 复制代码
cd backend
pytest tests/test_api_trip.py -q        # API 测试
pytest tests/test_services_trip.py -q   # 服务层测试
pytest tests/test_rag_retriever.py -q   # RAG 测试

10.2 手动验证

bash 复制代码
# 启动后端
uvicorn app.api.main:app --host 0.0.0.0 --port 8000

# 访问 Swagger UI
http://127.0.0.1:8000/docs

# 测试行程生成
curl -X POST "http://127.0.0.1:8000/trip/generate" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "大理",
    "start_date": "2024-07-01",
    "end_date": "2024-07-03",
    "travelers": 2,
    "budget": 3000,
    "preferences": ["美食", "自然风景"],
    "pace": "轻松"
  }'

11. 关键技术亮点

11.1 RAG 在线优化

优化项 效果
LLM-based Query Rewrite Top1 命中率 80%→86.7%
Cross-encoder Rerank Top1 命中率 86.7%→93.3%
噪声预过滤 减少低质量片段干扰
Rerank 缓存 延迟 728ms→425ms(降 41.6%)

11.2 缓存设计

  • 多层缓存:天气/地图/RAG/Rerank 各自独立配置
  • 优雅降级:Redis 不可用时自动跳过,不影响主流程
  • 统一前缀trip_planner:{type}:{key} 避免冲突

11.3 异常处理

  • LLM 调用失败:回退到规则实现
  • 地图服务失败:跳过 enrich,保留基础行程
  • 缓存失败:跳过缓存,不影响业务

12. 学习路径建议

  1. 入门 :先理解 schemas.pydb_models.py,掌握数据结构
  2. 核心流程 :阅读 trip_service.py,理解行程编排逻辑
  3. LLM 调用 :学习 trip_planner_agent.py 的 Prompt 设计
  4. RAG 检索 :深入 vector_db.pyretriever.py
  5. 外部集成 :了解 map_service.pyweather_service.py
  6. 实战:运行测试、调试 RAG、修改 Prompt

13. 常见问题

Q1:如何添加新目的地攻略?

  1. backend/data/ 目录下新建 {city}_guide.md
  2. 执行 python scripts/ingest_data.py 重新入库
  3. rag_tool.py 中添加目的地相关的关键词规则

Q2:如何开启缓存?

  1. 启动 Redis:docker run -d --name tripplanner-redis -p 6379:6379 redis:7
  2. .env 中设置 REDIS_ENABLED=true
  3. 重启后端服务

Q3:地图信息不显示?

检查:

  • AMAP_API_KEY 是否配置正确
  • ENABLE_AMAP_ENRICHMENT 是否为 true
  • 网络是否能访问高德 API

附录:核心文件职责速查

文件 职责 关键功能
app/config.py 配置中心 环境变量、数据库连接
app/api/main.py API入口 FastAPI应用配置、路由注册
app/api/routes/trip.py 行程路由 生成/编辑/保存/查询/删除
app/services/trip_service.py 业务编排 行程生成、预算计算、地图补全
app/services/cache_service.py 缓存管理 Redis封装、优雅降级
app/services/map_service.py 地图服务 POI搜索、地理编码、路线估算
app/agents/trip_planner_agent.py LLM调用 行程生成、单日编辑
app/agents/tools/rag_tool.py Query改写 LLM-based/规则级
app/rag/vector_db.py 向量检索 Chroma入库与查询
app/rag/retriever.py 检索封装 Rerank、缓存
app/models/schemas.py 数据模型 Pydantic请求/响应
app/models/db_models.py 数据库模型 SQLAlchemy表定义

本文档基于智旅云图项目 v0.1.0 版本编写

相关推荐
EMA1 小时前
langGraph学习指南1
人工智能
硬件学长森哥1 小时前
AI编程下程序员生存探索
人工智能
传说之后1 小时前
Go 网络编程:从 TCP 字节流到自定义协议设计
后端·架构
Rust研习社1 小时前
手把手带你使用 Bacon 高效开发应用
后端·rust·编程语言
果汁华1 小时前
LangChain 深度解析:从 Prompt 调用到 Agent 应用编排框架
人工智能·langchain·prompt
Nturmoils1 小时前
书签真正难的不是收藏,而是找回来:我是怎么做这个 Chrome 插件的
javascript·后端·浏览器
XovH1 小时前
Django 静态文件与媒体文件处理:CSS、JS 与用户上传图片的最佳实践
后端
bruce541101 小时前
讲讲 RTMate (WebSocket as A Service)中的消息的发布订阅机制
后端·微信小程序
zuozewei1 小时前
AI-7D-SATS平台的harness engineering设计:让 AI Agent 从“工具堆叠”长成“工程制品”
大数据·人工智能