Agent 层
修改记录
日期 |
变更 |
|---|---|
2026-07-18 |
从 backend.md 拆分独立 |
一、架构总览
Agent 层位于 HTTP 路由层和求解引擎层之间,负责 LLM 对话与工具调用。
路由层 (routes.py)
↓ POST /api/chat
Agent 层
├── chat.py 对话流调度
├── tools/ 工具注册与执行
├── commentator.py 评语生成
└── planner.py 规划调整
↓
引擎层 (engine/) ← 工具函数(poi_lookup 等)
二、目录结构
backend/agent/
├── chat.py 对话流:build_chat_messages / chat_stream / stream_chat
├── commentator.py 评语生成器:generate_commentary
├── planner.py 三指令规划器:add_poi / remove_poi / adjust_days
└── tools/
├── __init__.py 工具注册表 TOOL_REGISTRY
├── prompts.py 所有 LLM prompt 模板集中管理
├── poi.py POI 查询工具:poi_lookup / parse_biz_hours
└── rag.py BM25 检索引擎:search_rag() / RagEngine
三、对话流
SSE 协议格式
后端通过 text/event-stream 推送结构化事件:
type |
触发时机 |
前端行为 |
|---|---|---|
|
LLM 返回 tool_call 时 |
显示"正在查询..." |
|
工具执行完成后 |
渲染 POI 卡片至左侧待选栏 |
|
LLM 流式生成文字时 |
打字机效果追加 |
|
对话生成异常时 |
显示错误提示 |
|
全部输出完毕 |
结束 loading 状态 |
消息构建
build_chat_messages() 从 prompts.py 读取 CHAT_SYSTEM,附加规划上下文后组装为 OpenAI 格式。
RAG 上下文注入
每次调用 build_chat_messages() 时自动触发 BM25 全文检索(rag.py):
search_rag(query)对用户消息分词后检索docs/*.md+README.md取 top-3 相关片段,格式化为
相关知识:\n- [来源] 标题:片段...以
system角色注入消息列表(位于CHAT_SYSTEM之后,user 消息之前)
匹配策略:中文拆单字、英文空白分词,无需 jieba 等外部库。
调试模式
MOCK_MODE=True 时走 mock_stream_chat() 固定回复,无需 API Key。
正式部署应保持 MOCK_MODE=False。
四、工具系统
注册表
TOOL_REGISTRY 字典集中管理所有可调用工具(tools/__init__.py):
TOOL_REGISTRY: dict[str, Callable] = {
"poi_lookup": poi_lookup,
}
新增工具只需在 tools/ 下新建文件、实现函数、注册到 TOOL_REGISTRY。
主流程
用户消息 → build_chat_messages() + TOOL_DEFINITIONS
→ LLM 非流式首调
├─ tool_calls → 执行工具 → tool_result 追加 messages → LLM 二次调用 → SSE 流式回复
└─ text → SSE 直接流式输出
poi_lookup 工具
详见 tools/poi.py。
通过高德 API 查询 POI 坐标、地址和营业时间。自动识别酒店与景点:
酒店:
poi_type="hotel",时间窗0-1440(全天)景点:
poi_type="spot",时间窗由 LLM 解析opentime2
五、提示词管理
所有 LLM prompt 集中在 tools/prompts.py:
常量 |
用途 |
|---|---|
|
对话系统 prompt |
|
营业时间 LLM 解析模板 |
|
poi_lookup 工具定义(JSON schema) |
|
全部工具定义列表 |
六、评语与规划调整
commentator.py
generate_commentary(plan_result) → 自然语言评语。规则模板 + LLM 润色混合模式。
详见 docs/产品路线图.md 第一阶段。
planner.py
三指令规划器,当前函数已就绪但未接入 Function Calling:
函数 |
功能 |
|---|---|
|
加景点后调用 |
|
去景点后重映射索引重算 |
|
调天数后重分配行程 |
目标:后续注册到 TOOL_REGISTRY 后,用户可通过对话调整方案。
七、数据流
Function Calling 流程
用户: "查一下广州的白云山"
→ POST /api/chat { message: "查一下广州的白云山" }
→ build_chat_messages() → [system, user]
→ OpenAI tools=TOOL_DEFINITIONS
→ LLM: tool_call → poi_lookup(city="广州", name="白云山")
→ 高德 API → 坐标/地址/营业时间
→ SSE: tool_result
→ pendingPois[] 追加 ← 前端左侧待选栏
→ messages 追加 tool result → LLM 二次调用
→ SSE: content → "找到了!白云山..."
→ SSE: done
RAG 检索流程
用户: "这个项目是做什么的"
→ POST /api/chat { message: "这个项目是做什么的" }
→ build_chat_messages()
├─ search_rag("这个项目是做什么的") → BM25 检索 docs/ 相关片段
└─ 注入 system message(知识段位于 user 之前)
→ OpenAI 无 tools 调用 → SSE 直接流式输出
→ SSE: content → "这是一个基于 VNS+ 引擎的..."
→ SSE: done