Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/chris-junhao_tripplanner-agent.json

1 line
28 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "chris-junhao/tripplanner-agent", "files": {"README.md": {"75704d5cf2780ea934c6099711f3a4663f4d6f94": {"t": 1785747274.346627, "n": 1600, "h": "5ff929c9a05acb9d", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划应用:后端用结构化 `Itinerary` 作为行程状态唯一真相源,结合 LLM 初始生成、工具化增量编辑、会话记忆、SQLite 持久化、真实高德交通与外部 API 降级;前端提供多轮聊天、会话管理、交通切换和路线地图。\n\n当前已实现的核心能力包括:\n\n- 多日行程生成:支持 `/generate` 和 `/chat` 新会话初始规划。\n- 需求澄清:新会话使用空 destination 占位;未初始化行程分别解析目的地和天数,信息缺失时定向追问,补充完整后不受澄清历史阻塞。\n- 多轮增量编辑:通过 `add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget` 修改现有状态。\n- 会话管理:按 `session_id` 保存和恢复行程及有限历史,支持自动命名、手动改名与删除。\n- 真实交通与时间线:为相邻活动查询高德路线,支持打车、公交、步行的逐段切换和整份行程一键切换;增量编辑后自动重算受影响天,并同步预算与活动时间线。\n- 路线地图:复用后端交通查询得到的 GCJ-02 活动坐标,支持按天绘制、筛选路线和编号标记。\n- 安全富文本:助手回复支持 Markdown,并在渲染前通过 DOMPurify 消毒。\n- 降级策略:LLM、天气、地图、SQLite 失败时返回结构化失败或跳过增强,不向用户抛异常栈。\n\n## 启动方式\n\n后端:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\npython -m pytest -q\npython -m uvicorn tripplanner.api:app --reload\n```\n\n通用 shell 中把激活命令替换为对应平台命令即可;也可以不建虚拟环境,直接在已有 Python 3.11+ 环境中安装依赖。\n\n`backend/.env` 由 `backend/.env.example` 复制得到。常用变量:\n\n- `LLM_PROVIDER=openai|deepseek`\n- `OPENAI_API_KEY` / `DEEPSEEK_API_KEY`\n- `AMAP_KEY`:高德地图;未配置时交通段增强会降级。\n- `QWEATHER_KEY`:和风天气;未配置时天气工具会降级。\n- `FRONTEND_ORIGIN=http://localhost:5173`:可用逗号配置多个来源,并自动补齐 `localhost` / `127.0.0.1` 本地别名。\n\n前端:\n\n```powershell\ncd frontend\nnpm install\nnpm run dev\n```\n\n默认后端地址是 `http://localhost:8000`,可在 `frontend/.env.local` 中设置:\n\n```text\nVITE_API_BASE=http://localhost:8000\nVITE_AMAP_JS_KEY=你的高德_JS_API_Key\n```\n\n更多文档:\n\n- [权威设计文档](docs/DESIGN.md)\n- [API 参考](docs/API.md)\n- [后端设计](docs/BACKEND_DESIGN.md)\n- [开发进度](docs/PROGRESS.md)\n- [前端说明](frontend/README.md)\n"}, "03fc2d50bc6f1640f1b5a37e6c70047272d6f136": {"t": 1785772077.4882166, "n": 1600, "h": "5ff929c9a05acb9d", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划应用:后端用结构化 `Itinerary` 作为行程状态唯一真相源,结合 LLM 初始生成、工具化增量编辑、会话记忆、SQLite 持久化、真实高德交通与外部 API 降级;前端提供多轮聊天、会话管理、交通切换和路线地图。\n\n当前已实现的核心能力包括:\n\n- 多日行程生成:支持 `/generate` 和 `/chat` 新会话初始规划。\n- 需求澄清:新会话使用空 destination 占位;未初始化行程分别解析目的地和天数,信息缺失时定向追问,补充完整后不受澄清历史阻塞。\n- 多轮增量编辑:通过 `add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget` 修改现有状态。\n- 会话管理:按 `session_id` 保存和恢复行程及有限历史,支持自动命名、手动改名与删除。\n- 真实交通与时间线:为相邻活动查询高德路线,支持打车、公交、步行的逐段切换和整份行程一键切换;增量编辑后自动重算受影响天,并同步预算与活动时间线。\n- 路线地图:复用后端交通查询得到的 GCJ-02 活动坐标,支持按天绘制、筛选路线和编号标记。\n- 安全富文本:助手回复支持 Markdown,并在渲染前通过 DOMPurify 消毒。\n- 降级策略:LLM、天气、地图、SQLite 失败时返回结构化失败或跳过增强,不向用户抛异常栈。\n\n## 启动方式\n\n后端:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\npython -m pytest -q\npython -m uvicorn tripplanner.api:app --reload\n```\n\n通用 shell 中把激活命令替换为对应平台命令即可;也可以不建虚拟环境,直接在已有 Python 3.11+ 环境中安装依赖。\n\n`backend/.env` 由 `backend/.env.example` 复制得到。常用变量:\n\n- `LLM_PROVIDER=openai|deepseek`\n- `OPENAI_API_KEY` / `DEEPSEEK_API_KEY`\n- `AMAP_KEY`:高德地图;未配置时交通段增强会降级。\n- `QWEATHER_KEY`:和风天气;未配置时天气工具会降级。\n- `FRONTEND_ORIGIN=http://localhost:5173`:可用逗号配置多个来源,并自动补齐 `localhost` / `127.0.0.1` 本地别名。\n\n前端:\n\n```powershell\ncd frontend\nnpm install\nnpm run dev\n```\n\n默认后端地址是 `http://localhost:8000`,可在 `frontend/.env.local` 中设置:\n\n```text\nVITE_API_BASE=http://localhost:8000\nVITE_AMAP_JS_KEY=你的高德_JS_API_Key\n```\n\n更多文档:\n\n- [权威设计文档](docs/DESIGN.md)\n- [API 参考](docs/API.md)\n- [后端设计](docs/BACKEND_DESIGN.md)\n- [开发进度](docs/PROGRESS.md)\n- [前端说明](frontend/README.md)\n"}, "502947bbdd789bdaa57832ed3033a3e8267d8772": {"t": 1785772078.7766109, "n": 1598, "h": "207460620395bc51", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划应用:后端用结构化 `Itinerary` 作为行程状态唯一真相源,结合 LLM 初始生成、工具化增量编辑、会话记忆、SQLite 持久化、真实高德交通与外部 API 降级;前端提供多轮聊天、会话管理、交通切换和路线地图。\n\n当前已实现的核心能力包括:\n\n- 多日行程生成:支持 `/generate` 和 `/chat` 新会话初始规划。\n- 需求澄清:新会话使用空 destination 占位;未初始化行程分别解析目的地和天数,信息缺失时定向追问,补充完整后不受澄清历史阻塞。\n- 多轮增量编辑:通过 `add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget` 修改现有状态。\n- 会话管理:按 `session_id` 保存和恢复行程及有限历史,支持自动命名、手动改名与删除。\n- 真实交通与时间线:为相邻活动查询高德路线,支持打车、公交、步行的逐段切换和整份行程一键切换;增量编辑后自动重算受影响天,并同步预算与活动时间线。\n- 路线地图:复用后端交通查询得到的 GCJ-02 活动坐标,在前端按天绘制路线和编号标记。\n- 安全富文本:助手回复支持 Markdown,并在渲染前通过 DOMPurify 消毒。\n- 降级策略:LLM、天气、地图、SQLite 失败时返回结构化失败或跳过增强,不向用户抛异常栈。\n\n## 启动方式\n\n后端:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\npython -m pytest -q\npython -m uvicorn tripplanner.api:app --reload\n```\n\n通用 shell 中把激活命令替换为对应平台命令即可;也可以不建虚拟环境,直接在已有 Python 3.11+ 环境中安装依赖。\n\n`backend/.env` 由 `backend/.env.example` 复制得到。常用变量:\n\n- `LLM_PROVIDER=openai|deepseek`\n- `OPENAI_API_KEY` / `DEEPSEEK_API_KEY`\n- `AMAP_KEY`:高德地图;未配置时交通段增强会降级。\n- `QWEATHER_KEY`:和风天气;未配置时天气工具会降级。\n- `FRONTEND_ORIGIN=http://localhost:5173`:可用逗号配置多个来源,并自动补齐 `localhost` / `127.0.0.1` 本地别名。\n\n前端:\n\n```powershell\ncd frontend\nnpm install\nnpm run dev\n```\n\n默认后端地址是 `http://localhost:8000`,可在 `frontend/.env.local` 中设置:\n\n```text\nVITE_API_BASE=http://localhost:8000\nVITE_AMAP_JS_KEY=你的高德_JS_API_Key\n```\n\n更多文档:\n\n- [权威设计文档](docs/DESIGN.md)\n- [API 参考](docs/API.md)\n- [后端设计](docs/BACKEND_DESIGN.md)\n- [开发进度](docs/PROGRESS.md)\n- [前端说明](frontend/README.md)\n"}, "bd2258842c31101d98e0ab4c34bfe3af8ad7463a": {"t": 1785772079.950958, "n": 1309, "h": "bfaa5a2922b64eff", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划应用:后端用结构化 `Itinerary` 作为行程状态唯一真相源,结合 LLM 初始生成、工具化增量编辑、会话记忆、SQLite 持久化、真实高德交通与外部 API 降级,前端提供多轮聊天和可交互的行程展示。\n\n当前已实现的核心能力包括:\n\n- 多日行程生成:支持 `/generate` 和 `/chat` 新会话初始规划。\n- 多轮增量编辑:通过 `add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget` 修改现有状态。\n- 会话管理:按 `session_id` 保存和恢复行程、最近历史与滚动摘要。\n- 真实交通与时间线:为相邻活动查询高德路线,支持打车、公交、步行的逐段切换和整份行程一键切换;增量编辑后自动重算受影响天,并同步预算与活动时间线。\n- 降级策略:LLM、天气、地图、SQLite 失败时返回结构化失败或跳过增强,不向用户抛异常栈。\n\n## 启动方式\n\n后端:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\npython -m pytest -q\npython -m uvicorn tripplanner.api:app --reload\n```\n\n通用 shell 中把激活命令替换为对应平台命令即可;也可以不建虚拟环境,直接在已有 Python 3.11+ 环境中安装依赖。\n\n`backend/.env` 由 `backend/.env.example` 复制得到。常用变量:\n\n- `LLM_PROVIDER=openai|deepseek`\n- `OPENAI_API_KEY` / `DEEPSEEK_API_KEY`\n- `AMAP_KEY`:高德地图;未配置时交通段增强会降级。\n- `QWEATHER_KEY`:和风天气;未配置时天气工具会降级。\n- `FRONTEND_ORIGIN=http://localhost:5173`\n\n前端:\n\n```powershell\ncd frontend\nnpm install\nnpm run dev\n```\n\n默认后端地址是 `http://localhost:8000`,可在 `frontend/.env.local` 中设置:\n\n```text\nVITE_API_BASE=http://localhost:8000\n```\n\n更多文档:\n\n- [API 参考](docs/API.md)\n- [后端设计](docs/BACKEND_DESIGN.md)\n- [开发进度](docs/PROGRESS.md)\n- [前端说明](frontend/README.md)\n"}, "08074b6fa1453069fd3e9694083e5c09b0e6f147": {"t": 1785772081.3256373, "n": 1278, "h": "4fc32a94db331316", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划应用:后端用结构化 `Itinerary` 作为行程状态唯一真相源,结合 LLM 初始生成、工具化增量编辑、会话记忆、SQLite 持久化、交通时间线和外部 API 降级,前端提供多轮聊天与右侧行程展示。\n\n当前已实现的核心能力包括:\n\n- 多日行程生成:支持 `/generate` 和 `/chat` 新会话初始规划。\n- 多轮增量编辑:通过 `add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget` 修改现有状态。\n- 会话管理:按 `session_id` 保存和恢复行程、最近历史与滚动摘要。\n- 交通与时间线:生成后为相邻活动补交通段,并通过 timeline 接口计算活动起止时间。\n- 降级策略:LLM、天气、地图、SQLite 失败时返回结构化失败或跳过增强,不向用户抛异常栈。\n\n## 启动方式\n\n后端:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\npython -m pytest -q\npython -m uvicorn tripplanner.api:app --reload\n```\n\n通用 shell 中把激活命令替换为对应平台命令即可;也可以不建虚拟环境,直接在已有 Python 3.11+ 环境中安装依赖。\n\n`backend/.env` 由 `backend/.env.example` 复制得到。常用变量:\n\n- `LLM_PROVIDER=openai|deepseek`\n- `OPENAI_API_KEY` / `DEEPSEEK_API_KEY`\n- `AMAP_KEY`:高德地图;未配置时交通段增强会降级。\n- `QWEATHER_KEY`:和风天气;未配置时天气工具会降级。\n- `FRONTEND_ORIGIN=http://localhost:5173`\n\n前端:\n\n```powershell\ncd frontend\nnpm install\nnpm run dev\n```\n\n默认后端地址是 `http://localhost:8000`,可在 `frontend/.env.local` 中设置:\n\n```text\nVITE_API_BASE=http://localhost:8000\n```\n\n更多文档:\n\n- [API 参考](docs/API.md)\n- [后端设计](docs/BACKEND_DESIGN.md)\n- [开发进度](docs/PROGRESS.md)\n- [前端说明](frontend/README.md)\n"}, "66cac6d4521099f05cb4fc81c0ec8e306ba04d3d": {"t": 1785772083.4368763, "n": 7481, "h": "d07a2ff8135d3b67", "c": "# TripPlanner Agent\n\nTripPlanner Agent 是一个对话式旅行规划后端。它用结构化 `Itinerary` 作为行程状态的唯一真相源,通过 LLM 生成初始行程,并用工具调用循环支持多轮增量编辑、预算重规划、外部天气/地图查询降级、会话记忆、SQLite 持久化和调用轨迹观测。\n\n当前仓库的可运行部分是 `backend/`。`frontend/` 目前只是占位,Vue 前端尚未实现。\n\n详细设计见 [docs/DESIGN.md](docs/DESIGN.md),阶段开发记录见 [docs/PROGRESS.md](docs/PROGRESS.md)。\n\n## 当前能力\n\n- 结构化行程模型:`Activity`、`DayPlan`、`Itinerary` 均有稳定 id。\n- 一次性行程生成:`POST /generate` 调用 LLM 生成符合 Pydantic schema 的行程。\n- 预算汇总与重规划:`POST /budget` 计算预算,`POST /replan-budget` 在超预算时反馈式重规划。\n- 增量编辑工具:`add_activity`、`remove_activity`、`replace_activity`、`move_activity`、`adjust_budget`。\n- 统一工具调用循环:`run_turn` 让 LLM 选择工具,系统执行并回填结果。\n- Memory:会话以当前 `Itinerary` 为 SSOT,历史只保留窗口和滚动摘要。\n- SQLite 持久化:`session_id` 会话可保存并在服务重启后恢复。\n- 外部工具:和风天气、高德地图查询已接入工具注册;无 key、超时或失败时返回结构化不可用结果,不阻塞主流程。\n- 调用轨迹:`/chat` 请求带 `debug=true` 时返回结构化 `trace` 和可读 `trace_text`。\n\n## 技术栈\n\n- Python 3.11+\n- FastAPI / Uvicorn\n- Pydantic v2\n- OpenAI-compatible SDK,支持 OpenAI / DeepSeek 配置\n- SQLite\n- httpx\n- pytest\n\n## 项目结构\n\n```text\ntripplanner-agent/\n backend/\n tripplanner/\n api.py # FastAPI 入口\n agent.py # 统一工具调用循环 run_turn\n budget.py # 预算汇总与重规划\n generator.py # 结构化行程生成\n llm.py # LLM wrapper\n memory.py # 会话记忆,状态 SSOT + 历史窗口/摘要\n models.py # Pydantic 数据模型\n storage.py # SQLite 会话持久化\n trace.py # Agent 调用轨迹\n tools/\n editing.py # 增量编辑工具\n maps.py # 高德地图查询与降级\n registry.py # 工具 schema 与 dispatch\n weather.py # 和风天气查询与降级\n tests/\n .env.example\n requirements.txt\n pyproject.toml\n docs/\n DESIGN.md\n PROGRESS.md\n frontend/ # 占位;Vue 前端未实现\n AGENTS.md\n README.md\n```\n\n## 本地运行\n\n以下命令在仓库根目录执行,Windows PowerShell 示例:\n\n```powershell\ncd backend\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install -r requirements.txt\nCopy-Item .env.example .env\n```\n\n`.env` 里的变量来自 [backend/.env.example](backend/.env.example):\n\n```text\nOPENAI_API_KEY=\nDEEPSEEK_API_KEY=\nAMAP_KEY=\nQWEATHER_KEY=\nOPENAI_MODEL=gpt-4o-mini\nOPENAI_BASE_URL=\nDEEPSEEK_MODEL=deepseek-chat\nDEEPSEEK_BASE_URL=https://api.deepseek.com\nLLM_PROVIDER=openai\nLLM_TIMEOUT_SECONDS=30\n```\n\n说明:\n- `OPENAI_API_KEY`:使用 OpenAI provider 时需要。\n- `DEEPSEEK_API_KEY`:`LLM_PROVIDER=deepseek` 时需要。\n- `AMAP_KEY`:高德地图工具使用;未配置时该工具返回不可用,主流程继续。\n- `QWEATHER_KEY`:和风天气工具使用;未配置时该工具返回不可用,主流程继续。\n- 没有任何 LLM key 时,依赖 LLM 的 `/generate`、`/chat`、`/replan-budget` 会返回结构化不可用结果;纯本地的 `/health`、`/budget` 和测试仍可运行。\n\n运行测试:\n\n```powershell\npython -m pytest -q\n```\n\n启动后端:\n\n```powershell\npython -m uvicorn tripplanner.api:app --reload\n```\n\n健康检查:\n\n```powershell\nInvoke-RestMethod http://127.0.0.1:8000/health\n```\n\n返回:\n\n```json\n{\"status\":\"ok\"}\n```\n\nSQLite 默认数据库文件是 `backend/tripplanner.sqlite3`,已被 `.gitignore` 忽略。\n\n## API 用例\n\n以下示例假设服务运行在 `http://127.0.0.1:8000`。\n\n### GET /health\n\n```bash\ncurl http://127.0.0.1:8000/health\n```\n\n```json\n{\"status\":\"ok\"}\n```\n\n### POST /generate\n\n请求字段来自 `GenerateRequest`:`destination`、`days`、`budget_limit`、`preferences`。\n\n```bash\ncurl -X POST http://127.0.0.1:8000/generate \\\n -H \"Content-Type: application/json\" \\\n -d '{\"destination\":\"Chengdu\",\"days\":2,\"budget_limit\":2000,\"preferences\":[\"food\",\"no hiking\"]}'\n```\n\n成功时返回 `Itinerary`。LLM 不可用时返回 HTTP 503:\n\n```json\n{\"status\":\"llm_unavailable\",\"message\":\"The itinerary generation service is temporarily unavailable.\"}\n```\n\n### POST /budget\n\n`/budget` 不调用 LLM,只计算传入 itinerary 的费用。\n\n```bash\ncurl -X POST http://127.0.0.1:8000/budget \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"id\":\"trip0001\",\n \"destination\":\"Chengdu\",\n \"days\":1,\n \"budget_limit\":500,\n \"preferences\":[\"food\"],\n \"plan\":[{\n \"id\":\"day00001\",\n \"day_index\":1,\n \"activities\":[{\n \"id\":\"act00001\",\n \"name\":\"Museum\",\n \"type\":\"景点\",\n \"duration_min\":120,\n \"est_cost\":80\n }]\n }],\n \"lodging_cost\":200,\n \"transport_cost\":50\n }'\n```\n\n响应:\n\n```json\n{\n \"activity_cost\":80.0,\n \"lodging_cost\":200.0,\n \"transport_cost\":50.0,\n \"total_cost\":330.0,\n \"budget_limit\":500.0,\n \"is_over_budget\":false,\n \"over_by\":0.0\n}\n```\n\n### POST /replan-budget\n\n请求字段来自 `ReplanBudgetRequest`:`itinerary` 和可选 `max_iters`。\n\n```bash\ncurl -X POST http://127.0.0.1:8000/replan-budget \\\n -H \"Content-Type: application/json\" \\\n -d '{\"itinerary\":{\"id\":\"trip0001\",\"destination\":\"Chengdu\",\"days\":1,\"budget_limit\":100,\"preferences\":[],\"plan\":[],\"lodging_cost\":0,\"transport_cost\":0},\"max_iters\":2}'\n```\n\n未超预算时不会调用 LLM,直接返回:\n\n```json\n{\n \"status\":\"within_budget\",\n \"itinerary\":{\"id\":\"trip0001\",\"destination\":\"Chengdu\",\"days\":1,\"budget_limit\":100.0,\"preferences\":[],\"plan\":[],\"lodging_cost\":0.0,\"transport_cost\":0.0},\n \"budget\":{\"activity_cost\":0.0,\"lodging_cost\":0.0,\"transport_cost\":0.0,\"total_cost\":0.0,\"budget_limit\":100.0,\"is_over_budget\":false,\"over_by\":0.0},\n \"iterations\":0\n}\n```\n\n### POST /chat:显式 state 路径\n\n请求字段来自 `ChatRequest`:`message`、可选 `state`、`history`、`max_steps`、`session_id`、`debug`。\n\n```bash\ncurl -X POST http://127.0.0.1:8000/chat \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"message\":\"Remove the museum\",\n \"state\":{\n \"id\":\"trip0001\",\n \"destination\":\"Chengdu\",\n \"days\":1,\n \"budget_limit\":500,\n \"preferences\":[],\n \"plan\":[{\n \"id\":\"day00001\",\n \"day_index\":1,\n \"activities\":[{\n \"id\":\"act00001\",\n \"name\":\"Museum\",\n \"type\":\"景点\",\n \"duration_min\":120,\n \"est_cost\":80\n }]\n }],\n \"lodging_cost\":0,\n \"transport_cost\":0\n },\n \"history\":[],\n \"max_steps\":5\n }'\n```\n\n成功时返回 `TurnSuccess`:\n\n```json\n{\n \"status\":\"ok\",\n \"state\": {\"id\":\"trip0001\"},\n \"reply\":\"...\",\n \"operations\":[]\n}\n```\n\n上例中的 `state` 为简化展示,真实响应会包含完整 `Itinerary`。\n\n### POST /chat:session_id 会话路径\n\n创建新 session 时必须同时传 `session_id` 和初始 `state`:\n\n```bash\ncurl -X POST http://127.0.0.1:8000/chat \\\n -H \"Content-Type: application/json\" \\\n -d '{\"session_id\":\"demo-session\",\"message\":\"Keep this itinerary\",\"state\":{\"id\":\"trip0001\",\"destination\":\"Chengdu\",\"days\":1,\"budget_limit\":500,\"preferences\":[],\"plan\":[],\"lodging_cost\":0,\"transport_cost\":0}}'\n```\n\n已有 session 后续可以只传:\n\n```bash\ncurl -X POST http://127.0.0.1:8000/chat \\\n -H \"Content-Type: application/json\" \\\n -d '{\"session_id\":\"demo-session\",\"message\":\"Lower the budget to 400\"}'\n```\n\nsession 数据会写入 SQLite;服务重启后可按 `session_id` 恢复。\n\n### POST /chat:debug 调用轨迹\n\n`debug=true` 时,响应会额外包含 `trace` 和 `trace_text`:\n\n```bash\ncurl -X POST http://127.0.0.1:8000/chat \\\n -H \"Content-Type: application/json\" \\\n -d '{\"debug\":true,\"message\":\"Lower the budget\",\"state\":{\"id\":\"trip0001\",\"destination\":\"Chengdu\",\"days\":1,\"budget_limit\":500,\"preferences\":[],\"plan\":[],\"lodging_cost\":0,\"transport_cost\":0}}'\n```\n\n响应字段示例:\n\n```json\n{\n \"status\":\"ok\",\n \"state\": {},\n \"reply\":\"...\",\n \"operations\": [],\n \"trace\": [\n {\"type\":\"turn_start\",\"message\":\"Agent turn started.\",\"details\":{\"user_message\":\"Lower the budget\"}}\n ],\n \"trace_text\":\"User: Lower the budget\\nReply: ...\"\n}\n```\n\n### GET /sessions\n\n```bash\ncurl http://127.0.0.1:8000/sessions\n```\n\n```json\n{\"sessions\":[\"demo-session\"]}\n```\n\n### GET /session/{session_id}/itinerary\n\n```bash\ncurl http://127.0.0.1:8000/session/demo-session/itinerary\n```\n\n存在时返回当前 session 的 `Itinerary`;不存在时返回 HTTP 404:\n\n```json\n{\"status\":\"not_found\",\"message\":\"Session not found.\"}\n```\n\n## 开发备注\n\n- 所有测试都 mock LLM 或外部服务,不需要真实 key。\n- 外部天气/地图工具只作为优化信息源;不可用时返回结构化不可用结果,主流程继续。\n- 当前没有 Vue 前端;请使用 API 或测试验证功能。\n"}, "c422c8f0db08befd3f41b474a05c113576a274f1": {"t": 1785772087.958666, "n": 3184, "h": "af00cd04849fd9c2", "c": "# TripPlanner Agent · 对话式旅行规划助手\n\n> 输入目的地、天数、预算和偏好,Agent 自动生成结构化的每日行程与预算明细,\n> 并支持用自然语言多轮修改计划——它**记得**你的行程,做的是**局部增量调整**,而不是每次推倒重来。\n\n<!-- 建议在这里放一张 demo GIF:左侧聊天、右侧行程卡片实时更新 -->\n<!-- ![demo](docs/demo.gif) -->\n\n---\n\n## ✨ 这个项目想证明的事\n\n它不是一个 \"ChatGPT 套壳\"。核心价值在于一个**有状态的增量规划引擎**:把\"改第二天少一个景点\"\"预算降到 3000\"\"第三天我想去海边\"这类自然语言意图,翻译成对结构化行程状态的精确编辑,而不是整份重新生成。\n\n| Agent 能力 | 在本项目中的体现 |\n|---|---|\n| **任务规划 (Planning)** | 根据约束生成多日行程;超预算时触发反馈式重规划 |\n| **结构化输出** | Pydantic 定义行程数据模型 + schema 校验 + 多级降级 |\n| **对话记忆 (Memory)** | 结构化行程状态作为唯一真相源,对话历史只做窗口/摘要 |\n| **工具调用 (Tool Calling)** | 统一的工具调用循环,同时驱动「行程编辑」与「外部 API」 |\n| **多轮交互** | 用户像聊天一样反复调整,Agent 始终基于当前状态做局部更新 |\n\n> 详细的工程设计、数据模型与关键权衡见 [DESIGN.md](docs/DESIGN.md)。\n\n---\n\n## 🧱 架构总览\n\n```mermaid\nflowchart LR\n U[用户] <--> UI[对话界面 · Streamlit]\n UI <--> O[Agent Orchestrator<br/>统一工具调用循环]\n O <--> LLM[LLM · OpenAI / DeepSeek]\n O <--> STATE[(行程状态<br/>Single Source of Truth)]\n STATE <--> DB[(SQLite 持久化)]\n\n O --> E[编辑工具<br/>add / remove / replace]\n O --> B[预算工具<br/>汇总 + 约束检查]\n O --> W[天气 API · 和风]\n O --> M[地图 API · 高德]\n```\n\n关键点:**行程编辑**和**外部数据查询**走的是同一套工具调用机制。新增一个外部能力 ≈ 往工具列表里多注册一个函数,不动核心架构。\n\n---\n\n## 🚀 快速开始\n\n```bash\n# 1. 克隆并安装依赖\ngit clone https://github.com/<your-name>/tripplanner-agent.git\ncd tripplanner-agent\ncd backend\npip install -r requirements.txt\n\n# 2. 配置密钥(复制模板后填入,绝不提交到 git)\ncp .env.example .env\n# OPENAI_API_KEY / DEEPSEEK_API_KEY\n# AMAP_KEY 高德地图(可选,阶段 4 用)\n# QWEATHER_KEY 和风天气(可选,阶段 4 用)\n\n# 3. 命令行跑通核心链路\npython -m tripplanner.cli\n\n# 4. 启动后端 API\nuvicorn tripplanner.api:app --reload\n```\n\n> 所有密钥通过环境变量注入,`.env` 已加入 `.gitignore`,不会进入版本库。\n\n---\n\n## 💬 使用示例\n\n```\n你:帮我规划成都 3 天,预算 4000,爱美食、不想爬山\nAgent:已生成 3 天行程(总预算 ¥3,820)。Day1 宽窄巷子 + 火锅…\n\n你:第二天太满了,减一个景点\nAgent:已从 Day2 移除「大熊猫基地下午场」,当日时长从 9.5h 降到 7h。\n\n你:预算降到 3000\nAgent:检测到当前 ¥3,820 超出新预算。已将 2 顿正餐降档、合并一次打车,\n 现总预算 ¥2,910。是否保留这些调整?\n\n你:第三天我想去海边\nAgent:成都周边无海;最近海滨需 ~1500km。要不要改为「都江堰 + 青城山」\n 的近郊水景方案?\n```\n\n每一步 Agent 都基于**当前行程状态**做最小改动,并解释改了什么、对预算/时长的影响。\n\n---\n\n## 🗂️ 项目结构\n\n```\ntripplanner-agent/\n├── backend/\n│ ├── tripplanner/\n│ │ ├── models.py # Pydantic 行程数据模型(带稳定 ID)\n│ │ ├── agent.py # 工具调用循环(orchestrator)\n│ │ ├── tools/\n│ │ │ ├── editing.py # add / remove / replace / adjust_budget\n│ │ │ ├── weather.py # 和风天气 + 降级\n│ │ │ └── maps.py # 高德距离/POI + 动线优化\n│ │ ├── memory.py # 状态 = 唯一真相源 + 历史窗口/摘要\n│ │ ├── budget.py # 费用汇总与约束满足\n│ │ ├── llm.py # LLM 调用 + structured outputs + 多级降级\n│ │ └── storage.py # SQLite 持久化\n│ ├── tests/ # 后端测试\n│ ├── .env.example\n│ ├── pyproject.toml\n│ └── requirements.txt\n├── frontend/ # Vue 前端占位\n├── docs/\n│ └── DESIGN.md\n├── .gitignore\n├── AGENTS.md\n└── README.md\n```\n\n---\n\n## 🛣️ 路线图 (Roadmap)\n\n- [ ] **阶段 0** 环境与骨架,跑通一次最简 LLM 调用\n- [ ] **阶段 1** 一次性生成结构化多日行程(Pydantic + schema 校验)\n- [ ] **阶段 2** 预算汇总 + 超预算反馈式重规划\n- [ ] **阶段 3** 多轮局部修改 + Memory(**核心亮点**)\n- [ ] **阶段 4** 接入和风天气 / 高德地图(Tool Calling)\n- [ ] **阶段 5** Streamlit 界面 + SQLite 持久化 + 评估场景\n\n> 开发原则:每个阶段先\"能跑\"再加功能;每个阶段产出都能独立演示。\n\n---\n\n## 🛠️ 技术栈\n\nPython · OpenAI / DeepSeek API · Pydantic(结构化数据模型)· SQLite(持久化)· Streamlit(界面)· 高德地图 & 和风天气(外部工具)\n\n---\n\n## 📄 License\n\nMIT\n"}}}}