|
|
@@ -32,7 +32,7 @@
|
|
|
**Interfaces:**
|
|
|
- Produces: FastAPI app 入口 `app.main:app`,`/health` 返回 200
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `pyproject.toml`**
|
|
|
+- [x] **Step 1: 创建 `pyproject.toml`**
|
|
|
|
|
|
```toml
|
|
|
[project]
|
|
|
@@ -70,7 +70,7 @@ select = ["E", "F", "I", "N", "W"]
|
|
|
ignore = ["E501"]
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `.env.example`**
|
|
|
+- [x] **Step 2: 创建 `.env.example`**
|
|
|
|
|
|
```bash
|
|
|
# LLM
|
|
|
@@ -101,7 +101,7 @@ LOG_LEVEL=info
|
|
|
CHROMA_DB_PATH=./data/chroma_db
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 创建 `.gitignore`**
|
|
|
+- [x] **Step 3: 创建 `.gitignore`**
|
|
|
|
|
|
```
|
|
|
__pycache__/
|
|
|
@@ -114,7 +114,7 @@ dist/
|
|
|
.pytest_cache/
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: 创建 `Dockerfile`**
|
|
|
+- [x] **Step 4: 创建 `Dockerfile`**
|
|
|
|
|
|
```dockerfile
|
|
|
FROM python:3.11-slim
|
|
|
@@ -132,9 +132,9 @@ EXPOSE 9000
|
|
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "9000"]
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: 创建 `app/__init__.py`**(空文件)
|
|
|
+- [x] **Step 5: 创建 `app/__init__.py`**(空文件)
|
|
|
|
|
|
-- [ ] **Step 6: 创建 `app/main.py`**
|
|
|
+- [x] **Step 6: 创建 `app/main.py`**
|
|
|
|
|
|
```python
|
|
|
from fastapi import FastAPI
|
|
|
@@ -153,7 +153,7 @@ async def shutdown():
|
|
|
pass # 后续 Phase 在此清理资源
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 7: 验证服务可启动**
|
|
|
+- [x] **Step 7: 验证服务可启动**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-langgraph
|
|
|
@@ -164,9 +164,9 @@ curl http://localhost:9000/health
|
|
|
kill %1
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 8: 创建 `app/api/__init__.py`**(空文件)
|
|
|
+- [x] **Step 8: 创建 `app/api/__init__.py`**(空文件)
|
|
|
|
|
|
-- [ ] **Step 9: 创建 `app/api/health.py`**
|
|
|
+- [x] **Step 9: 创建 `app/api/health.py`**
|
|
|
|
|
|
```python
|
|
|
from fastapi import APIRouter
|
|
|
@@ -178,7 +178,7 @@ async def health():
|
|
|
return {"status": "ok"}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 10: Commit**
|
|
|
+- [x] **Step 10: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -195,7 +195,7 @@ git commit -m "feat(langgraph): scaffold Python sidecar project"
|
|
|
**Interfaces:**
|
|
|
- Produces: `app.config.settings` — Pydantic Settings 单例,所有模块通过 `from app.config import settings` 读取
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `app/config.py`**
|
|
|
+- [x] **Step 1: 创建 `app/config.py`**
|
|
|
|
|
|
```python
|
|
|
from pydantic_settings import BaseSettings
|
|
|
@@ -246,14 +246,14 @@ class Settings(BaseSettings):
|
|
|
settings = Settings()
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `.env` 文件(从 `.env.example` 复制,填入真实 Key)**
|
|
|
+- [x] **Step 2: 创建 `.env` 文件(从 `.env.example` 复制,填入真实 Key)**
|
|
|
|
|
|
```bash
|
|
|
cp cfc-langgraph/.env.example cfc-langgraph/.env
|
|
|
# 手动编辑填入 LLM_API_KEY
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 验证配置可加载**
|
|
|
+- [x] **Step 3: 验证配置可加载**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-langgraph
|
|
|
@@ -261,7 +261,7 @@ python -c "from app.config import settings; print(settings.llm_model)"
|
|
|
# 预期输出: deepseek-chat
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: Commit**
|
|
|
+- [x] **Step 4: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -281,7 +281,7 @@ git commit -m "feat(langgraph): config management with pydantic-settings"
|
|
|
**Interfaces:**
|
|
|
- Produces: Phase 1 所需的请求/响应模型
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `app/models/__init__.py`**
|
|
|
+- [x] **Step 1: 创建 `app/models/__init__.py`**
|
|
|
|
|
|
```python
|
|
|
from .common import UserContext, SourceInfo
|
|
|
@@ -289,7 +289,7 @@ from .chat import ChatRequest, ChatResponse
|
|
|
from .recommend import RecommendRequest, RecommendResponse, RecommendItem
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `app/models/common.py`**
|
|
|
+- [x] **Step 2: 创建 `app/models/common.py`**
|
|
|
|
|
|
```python
|
|
|
from pydantic import BaseModel
|
|
|
@@ -310,7 +310,7 @@ class SourceInfo(BaseModel):
|
|
|
score: Optional[float] = None
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 创建 `app/models/chat.py`**
|
|
|
+- [x] **Step 3: 创建 `app/models/chat.py`**
|
|
|
|
|
|
```python
|
|
|
from pydantic import BaseModel
|
|
|
@@ -331,7 +331,7 @@ class ChatResponse(BaseModel):
|
|
|
trace_id: str = ""
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: 创建 `app/models/recommend.py`**
|
|
|
+- [x] **Step 4: 创建 `app/models/recommend.py`**
|
|
|
|
|
|
```python
|
|
|
from pydantic import BaseModel
|
|
|
@@ -362,7 +362,7 @@ class RecommendResponse(BaseModel):
|
|
|
trace_id: str = ""
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: Commit**
|
|
|
+- [x] **Step 5: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -382,14 +382,14 @@ git commit -m "feat(langgraph): pydantic models for API"
|
|
|
- Produces: `embeddings.get_embeddings()` → Embeddings 实例
|
|
|
- Produces: `retriever.RagRetriever` 类,提供 `retrieve(query, filters, k)` 方法
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `app/rag/__init__.py`**
|
|
|
+- [x] **Step 1: 创建 `app/rag/__init__.py`**
|
|
|
|
|
|
```python
|
|
|
from .embeddings import get_embeddings
|
|
|
from .retriever import RagRetriever
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `app/rag/embeddings.py`**
|
|
|
+- [x] **Step 2: 创建 `app/rag/embeddings.py`**
|
|
|
|
|
|
```python
|
|
|
from langchain_openai import OpenAIEmbeddings
|
|
|
@@ -408,7 +408,7 @@ def get_embeddings():
|
|
|
return _embeddings
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 创建 `app/rag/retriever.py`**
|
|
|
+- [x] **Step 3: 创建 `app/rag/retriever.py`**
|
|
|
|
|
|
```python
|
|
|
from langchain_chroma import Chroma
|
|
|
@@ -507,7 +507,7 @@ class RagRetriever:
|
|
|
return results[:k]
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: Commit**
|
|
|
+- [x] **Step 4: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -526,13 +526,13 @@ git commit -m "feat(langgraph): ChromaDB + RAG retriever infrastructure"
|
|
|
- Produces: `JavaClient` 类, 封装对所有 Java 接口的 HTTP 调用
|
|
|
- Produces: `get_published_articles()`, `search_products()`, `search_activities()`, `search_articles()`
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `app/tools/__init__.py`**
|
|
|
+- [x] **Step 1: 创建 `app/tools/__init__.py`**
|
|
|
|
|
|
```python
|
|
|
from .java_client import JavaClient
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `app/tools/java_client.py`**
|
|
|
+- [x] **Step 2: 创建 `app/tools/java_client.py`**
|
|
|
|
|
|
```python
|
|
|
import httpx
|
|
|
@@ -617,7 +617,7 @@ class JavaClient:
|
|
|
return {}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: Commit**
|
|
|
+- [x] **Step 3: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -641,7 +641,7 @@ git commit -m "feat(langgraph): Java HTTP client for tool calls"
|
|
|
- Consumes: `JavaClient`, `RagRetriever`, `ChatOpenAI`
|
|
|
- Produces: `POST /api/v1/recommend` 接口
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `app/tools/product_tools.py`**
|
|
|
+- [x] **Step 1: 创建 `app/tools/product_tools.py`**
|
|
|
|
|
|
```python
|
|
|
from langchain_core.tools import tool
|
|
|
@@ -701,11 +701,11 @@ async def search_article_by_keyword(keyword: str, limit: int = 5) -> str:
|
|
|
return "[]"
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `app/agents/__init__.py`**(空)
|
|
|
+- [x] **Step 2: 创建 `app/agents/__init__.py`**(空)
|
|
|
|
|
|
-- [ ] **Step 3: 创建 `app/graphs/__init__.py`**(空)
|
|
|
+- [x] **Step 3: 创建 `app/graphs/__init__.py`**(空)
|
|
|
|
|
|
-- [ ] **Step 4: 创建 `app/graphs/recommend_graph.py`**
|
|
|
+- [x] **Step 4: 创建 `app/graphs/recommend_graph.py`**
|
|
|
|
|
|
Phase 1 用**最简单的单步 Agent**(不涉及 StateGraph 复杂特性),后续 Phase 再升级为图编排:
|
|
|
|
|
|
@@ -788,7 +788,7 @@ class RecommendAgent:
|
|
|
return {"items": [], "text": content}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: 创建 `app/api/recommend.py`**
|
|
|
+- [x] **Step 5: 创建 `app/api/recommend.py`**
|
|
|
|
|
|
```python
|
|
|
from fastapi import APIRouter
|
|
|
@@ -839,7 +839,7 @@ async def recommend(req: RecommendRequest):
|
|
|
return RecommendResponse(items=[], source="error")
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 6: 修改 `app/main.py` 注册路由**
|
|
|
+- [x] **Step 6: 修改 `app/main.py` 注册路由**
|
|
|
|
|
|
```python
|
|
|
from fastapi import FastAPI
|
|
|
@@ -863,7 +863,7 @@ async def shutdown():
|
|
|
await client.close()
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 7: 验证 Recommend API**
|
|
|
+- [x] **Step 7: 验证 Recommend API**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-langgraph
|
|
|
@@ -876,7 +876,7 @@ curl -X POST http://localhost:9000/api/v1/recommend \
|
|
|
kill %1
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 8: Commit**
|
|
|
+- [x] **Step 8: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/
|
|
|
@@ -895,7 +895,7 @@ git commit -m "feat(langgraph): RecommendAgent with tool calling"
|
|
|
- Produces: `AiGateway.recommend()` — Java 端统一的 Python 调用入口,超时/异常自动 fallback
|
|
|
- Consumes: Python `POST /api/v1/recommend`
|
|
|
|
|
|
-- [ ] **Step 1: 在 `application.yml` 中新增配置**
|
|
|
+- [x] **Step 1: 在 `application.yml` 中新增配置**
|
|
|
|
|
|
```yaml
|
|
|
# application.yml 底部追加
|
|
|
@@ -908,7 +908,7 @@ python:
|
|
|
reset-timeout-ms: 30000
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `AiGateway.java`**
|
|
|
+- [x] **Step 2: 创建 `AiGateway.java`**
|
|
|
|
|
|
```java
|
|
|
package com.etotem.cfc.service;
|
|
|
@@ -1058,7 +1058,7 @@ public class AiGateway {
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 编译验证**
|
|
|
+- [x] **Step 3: 编译验证**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-backend
|
|
|
@@ -1066,7 +1066,7 @@ mvn clean compile -q
|
|
|
# 预期: BUILD SUCCESS
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: Commit**
|
|
|
+- [x] **Step 4: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-backend/src/main/java/com/etotem/cfc/service/AiGateway.java
|
|
|
@@ -1086,7 +1086,7 @@ git commit -m "feat(backend): AiGateway with circuit breaker for LangGraph"
|
|
|
- Consumes: `AiGateway.recommend()`
|
|
|
- 灰度策略: 5% 流量走 Python, 异常自动 fallback 现有逻辑
|
|
|
|
|
|
-- [ ] **Step 1: 修改 `RecommendationController.java`**
|
|
|
+- [x] **Step 1: 修改 `RecommendationController.java`**
|
|
|
|
|
|
```java
|
|
|
// 注入 AiGateway
|
|
|
@@ -1132,7 +1132,7 @@ public Result<List<RecommendationResult>> search(
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: 编译验证**
|
|
|
+- [x] **Step 2: 编译验证**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-backend
|
|
|
@@ -1140,7 +1140,7 @@ mvn clean compile -q
|
|
|
# 预期: BUILD SUCCESS
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: Commit**
|
|
|
+- [x] **Step 3: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-backend/src/main/java/com/etotem/cfc/controller/ai/RecommendationController.java
|
|
|
@@ -1154,7 +1154,7 @@ git commit -m "feat(backend): 5% recommend traffic routed to LangGraph"
|
|
|
**Files:**
|
|
|
- Create: `cfc-langgraph/docker-compose.yml`
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `docker-compose.yml`**
|
|
|
+- [x] **Step 1: 创建 `docker-compose.yml`**
|
|
|
|
|
|
```yaml
|
|
|
version: "3.8"
|
|
|
@@ -1181,7 +1181,7 @@ volumes:
|
|
|
langgraph-data:
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 2: Commit**
|
|
|
+- [x] **Step 2: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/docker-compose.yml
|
|
|
@@ -1197,9 +1197,9 @@ git commit -m "chore(langgraph): Docker Compose for local dev"
|
|
|
- Create: `cfc-langgraph/tests/conftest.py`
|
|
|
- Create: `cfc-langgraph/tests/test_recommend.py`
|
|
|
|
|
|
-- [ ] **Step 1: 创建 `tests/__init__.py`**(空文件)
|
|
|
+- [x] **Step 1: 创建 `tests/__init__.py`**(空文件)
|
|
|
|
|
|
-- [ ] **Step 2: 创建 `tests/conftest.py`**
|
|
|
+- [x] **Step 2: 创建 `tests/conftest.py`**
|
|
|
|
|
|
```python
|
|
|
import pytest
|
|
|
@@ -1218,7 +1218,7 @@ async def health_response(client):
|
|
|
return resp
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 3: 创建 `tests/test_recommend.py`**
|
|
|
+- [x] **Step 3: 创建 `tests/test_recommend.py`**
|
|
|
|
|
|
```python
|
|
|
import pytest
|
|
|
@@ -1264,7 +1264,7 @@ async def test_recommend_with_tags():
|
|
|
assert "source" in data
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 4: 运行测试**
|
|
|
+- [x] **Step 4: 运行测试**
|
|
|
|
|
|
```bash
|
|
|
cd cfc-langgraph
|
|
|
@@ -1274,7 +1274,7 @@ pytest tests/ -v
|
|
|
# test_recommend_with_tags 可能因 Java 后端未运行而返回空列表, 但不应该报错
|
|
|
```
|
|
|
|
|
|
-- [ ] **Step 5: Commit**
|
|
|
+- [x] **Step 5: Commit**
|
|
|
|
|
|
```bash
|
|
|
git add cfc-langgraph/tests/
|
|
|
@@ -1285,9 +1285,9 @@ git commit -m "test(langgraph): Phase 1 integration tests"
|
|
|
|
|
|
## 自审清单
|
|
|
|
|
|
-- [ ] 每个 Task 的产出物独立可测试
|
|
|
-- [ ] 没有 "TBD" / "TODO" 占位符
|
|
|
-- [ ] Python 侧没有直连 MySQL
|
|
|
-- [ ] Java 侧灰度开关 + 熔断器 + Fallback 三层保护
|
|
|
-- [ ] Docker Compose 可一键启动开发环境
|
|
|
-- [ ] Phase 1 产出物: 运行中的 Recommend API + 知识库基础设施
|
|
|
+- [x] 每个 Task 的产出物独立可测试
|
|
|
+- [x] 没有 "TBD" / "TODO" 占位符
|
|
|
+- [x] Python 侧没有直连 MySQL
|
|
|
+- [x] Java 侧灰度开关 + 熔断器 + Fallback 三层保护
|
|
|
+- [x] Docker Compose 可一键启动开发环境
|
|
|
+- [x] Phase 1 产出物: 运行中的 Recommend API + 知识库基础设施
|