用于Agentic Rag 的演示项目

yangxiaolong 14595e83a7 init:项目初始化 1 month ago
app 14595e83a7 init:项目初始化 1 month ago
data 14595e83a7 init:项目初始化 1 month ago
infra 14595e83a7 init:项目初始化 1 month ago
scripts 14595e83a7 init:项目初始化 1 month ago
tests 14595e83a7 init:项目初始化 1 month ago
.env 14595e83a7 init:项目初始化 1 month ago
.gitignore 14595e83a7 init:项目初始化 1 month ago
README.md 14595e83a7 init:项目初始化 1 month ago
pyproject.toml 14595e83a7 init:项目初始化 1 month ago
requirements.txt 14595e83a7 init:项目初始化 1 month ago
uv.lock 14595e83a7 init:项目初始化 1 month ago

README.md

电商售后 Agentic RAG 课程项目

技术栈:Python 3.11、FastAPI、LangGraph、Milvus、SQLite、Tavily、DeepSeek。

项目默认使用确定性的 demo 决策引擎和 Hash Embedding。无需模型 Key 即可完成数据准备、意图路由、Milvus 检索、SQL 查询、证据评分和多源执行。

1. 环境要求

  • Python 3.11
  • uv
  • 使用现有 Ubuntu Milvus 时,Windows 必须能访问其 19530 端口
  • 本地启动 Milvus 时,需要 Docker Desktop、WSL 2、至少 4 CPU 和 8 GB 内存

2. 安装

uv venv --python 3.11
uv sync --extra test

项目直接读取根目录下的 .env。DeepSeek、Tavily、Milvus 和数据路径等运行配置统一在该文件中维护。

按需安装可选能力:

# DeepSeek 模型适配。
uv sync --extra test --extra deepseek

# Tavily 网页搜索。
uv sync --extra test --extra web

# 本地 Sentence Transformers。
uv sync --extra test --extra embeddings

2.1 路径约定

仓库中使用相对路径,运行时根据 app/config.py 的位置解析为绝对路径,不依赖当前工作目录。

SQLITE_PATH=./data/shop.db
ORDERS_SOURCE_PATH=./data/source/orders.csv
DOCUMENTS_PATH=./data/documents

不要提交本机绝对路径和 .env。部署时如需使用仓库外的数据目录,可以在本地 .env 中配置绝对路径。

3. 连接或启动 Milvus

3.1 使用现有 Ubuntu Milvus

Ubuntu Milvus 的 19530 已映射到 Windows 时:

MILVUS_URI=http://localhost:19530
uv run python scripts/wait_for_milvus.py

Milvus 位于另一台主机时,将 localhost 替换为 Windows 可访问的 Ubuntu IP。

3.2 使用项目内 Compose

docker compose -f infra/milvus/docker-compose.yml config --quiet
docker compose -f infra/milvus/docker-compose.yml up -d
uv run python scripts/wait_for_milvus.py

4. 准备电商数据

本地数据分为两组:

  • data/source/orders.csv:脱敏订单,写入 SQLite orders 表。
  • data/documents/*.md:退货、运费和价保政策,切分后写入 Milvus。
uv run python scripts/prepare_data.py

准备脚本会重建课程数据库和 Milvus Collection。切换 Embedding 模型后也必须重新执行,不能混用不同模型或维度的向量。

5. 示例问题

类型 问题 预期工具
向量检索 耳机拆封后还能七日无理由退货吗? Milvus
SQL 查询 U1001 最近 30 天有几笔有效订单,实付总额是多少? SQLite
网页搜索 查询品牌官网关于 XPhone 15 Pro 的最新公告 Tavily
双源组合 统计 U1001 最近 30 天订单,并结合内部运费规则说明是否包邮 Milvus + SQLite
三源组合 统计 U1001 最近 30 天购买 XPhone 15 Pro 的订单金额,结合内部退货政策和品牌官网最新公告给出售后建议 Milvus + SQLite + Tavily

订单用户编号在课程数据中使用 U1001。生产系统必须从登录态或服务端认证上下文注入,不能信任模型从自然语言生成的用户编号。

6. 查看实际工具 Query

使用 --debug 时,CLI 会先打印每个工具实际执行的 Query、参数和状态,再输出完整响应:

uv run python -m app.cli `
  "统计 U1001 最近 30 天订单,并结合内部运费规则说明是否包邮" `
  --debug

输出结构:

=== 实际执行的工具查询 ===
- milvus_search: query='...' arguments={'policy_type': 'shipping_policy', 'top_k': 4}
- sql_query: query='...' arguments={'user_id': 'U1001', 'days': 30, ...}

API 请求设置 debug=true 时,响应中的 executed_queries 返回相同信息。普通请求不返回内部查询轨迹。

7. 自动化测试

uv run pytest
uv run python scripts/smoke_test.py

单元测试不访问真实模型或网页;Smoke Test 使用真实 Milvus 与 SQLite。

8. 启动 API

uv run uvicorn app.main:app --reload
$body = @{
  query = "统计 U1001 最近 30 天订单,并结合内部运费规则说明是否包邮"
  session_id = "demo"
  debug = $true
} | ConvertTo-Json

Invoke-RestMethod `
  -Method Post `
  -Uri "http://127.0.0.1:8000/query" `
  -ContentType "application/json" `
  -Body $body

Swagger UI:http://127.0.0.1:8000/docs

9. 配置 Web Search

.env 中配置 Tavily:

TAVILY_API_KEY=your-tavily-api-key
WEB_SEARCH_MAX_RESULTS=5

未配置 Key 时,Milvus 和 SQLite 路由不受影响;web_search 返回 WEB_SEARCH_NOT_CONFIGURED

运行时代码只通过 Settings 读取 TAVILY_API_KEY,不会从代码常量、请求参数或 CLI 参数接收 Key。

10. 切换到 DeepSeek

LLM_PROVIDER=deepseek
DEEPSEEK_API_KEY=your-deepseek-api-key
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL_NAME=deepseek-v4-flash
DEEPSEEK_ANSWER_THINKING=true

DeepSeekDecisionEngine 使用 Function Calling 输出 RouteDecisionQualityGrade。这两个结构化调用固定关闭 Thinking,避免 Thinking 模式与强制 tool_choice 冲突;最终答案是否使用 Thinking 由 DEEPSEEK_ANSWER_THINKING 控制。

DEEPSEEK_API_KEY 只通过 Settings 读取。所有 Key 使用 SecretStr 保存,打印配置对象时只显示掩码,不输出真实值。

11. 停止本地 Compose 服务

docker compose -f infra/milvus/docker-compose.yml down

数据目录位于 infra/milvus/volumes,已在 .gitignore 中排除。