阶段 7部署、上线、面试整理学习笔记主题Docker、部署、项目打磨学习目标能把项目从本地跑到容器里知道最基本的上线与运行方式并能在面试中用 3 分钟完整讲清楚项目。1. 阶段 7 的定位前面几个阶段你已经完成了阶段 3RAG 项目 阶段 4Tool Calling 与 Agent Loop 阶段 5升级为可讲的 Agent 项目 阶段 6观测、评测、安全阶段 7 要做的是最后一步把项目从“本地能跑”变成“别人也能稳定跑”也就是Dockerfile docker compose 环境变量 启动脚本 README 项目介绍稿 面试讲解材料这一阶段不是为了把你变成运维工程师而是让你具备最基本的工程交付能力。面试时可以这样说我对项目做了容器化封装使用 Dockerfile 构建后端服务镜像并通过 docker compose 编排 FastAPI 服务、向量数据库目录、日志目录和环境变量配置。这样项目不依赖本机环境面试官或协作者只需要配置.env再执行docker compose up --build就可以启动服务。2. Docker 是什么Docker 可以理解为把应用代码、运行环境、依赖库、启动命令一起打包成镜像然后在容器里运行。本地开发时你可能会遇到我电脑能跑你电脑跑不了 Python 版本不一样 依赖包版本不一样 系统库缺失 环境变量没配置 Chroma / SQLite / 数据目录路径不一致Docker 的价值就是解决这些环境一致性问题。2.1 Docker 中的核心概念概念解释Image 镜像应用运行所需环境的只读模板Container 容器镜像运行起来后的实例Dockerfile描述如何构建镜像的文件Registry存放镜像的仓库例如 Docker HubVolume持久化数据目录Network容器之间通信的网络Compose用一个 YAML 文件编排多个服务2.2 镜像和容器的关系Dockerfile - docker build - Image - docker run - Container类比理解Image 像“安装包” Container 像“运行中的程序” Dockerfile 像“安装包制作说明书”3. 为什么你的 Agent 项目需要 Docker你的项目包含很多组件FastAPI LangGraph OpenAI / LLM API Chroma / FAISS SQLite PDF 解析依赖 日志目录 .env 配置如果不容器化别人运行时可能会遇到Python 版本不一致依赖安装失败本地路径不一致.env忘记配置服务端口冲突启动命令不清楚Chroma 数据目录找不到SQLite 文件路径不对。Docker 化后运行方式可以变成cp.env.example .envdockercompose up--build这对面试演示非常重要。4. 项目部署目标阶段 7 的最低目标不是复杂上线而是做到1. 有 Dockerfile 2. 有 docker-compose.yml 3. 有 .env.example 4. 能构建镜像 5. 能启动 FastAPI 服务 6. 能挂载 data / logs / vectorstore 目录 7. README 写清楚启动方式 8. 有一页项目说明 9. 有 3 分钟项目介绍稿5. 推荐项目结构在阶段 6 的基础上最终项目可以长这样knowledge-agent-assistant/ README.md Dockerfile docker-compose.yml .dockerignore .env.example requirements.txt app/ main.py config.py api/ routes_chat.py routes_documents.py routes_logs.py schemas/ chat.py document.py common.py agent/ state.py graph.py nodes.py router.py prompts.py rag/ loader.py splitter.py embeddings.py vectorstore.py retriever.py citation.py tools/ registry.py knowledge_tools.py document_tools.py note_tools.py storage/ db.py models.py repositories.py checkpointer.py observability/ trace.py logger.py metrics.py evals/ dataset.json run_eval.py evaluators.py eval_report.md safety/ guardrails.py tool_policy.py confirmation.py data/ raw_pdfs/ chroma_db/ notes/ logs/ docs/ architecture.md project_one_page.md interview_script.md6. Dockerfile 基础Dockerfile 是构建镜像的说明书。对 FastAPI 项目来说一个基础 Dockerfile 可以这样写。6.1 推荐 Dockerfile# syntaxdocker/dockerfile:1 FROM python:3.11-slim WORKDIR /app ENV PYTHONDONTWRITEBYTECODE1 ENV PYTHONUNBUFFERED1 RUN apt-get update \ apt-get install -y --no-install-recommends \ build-essential \ curl \ rm -rf /var/lib/apt/lists/* COPY requirements.txt . RUN pip install --no-cache-dir --upgrade pip \ pip install --no-cache-dir -r requirements.txt COPY app ./app COPY data ./data COPY logs ./logs EXPOSE 8000 CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000]6.2 每一行的作用指令作用FROM python:3.11-slim选择 Python 基础镜像WORKDIR /app设置容器内工作目录ENV PYTHONDONTWRITEBYTECODE1不生成.pyc文件ENV PYTHONUNBUFFERED1日志实时输出RUN apt-get ...安装系统依赖COPY requirements.txt .先复制依赖文件RUN pip install ...安装 Python 依赖COPY app ./app复制项目代码EXPOSE 8000声明服务端口CMD ...容器启动时运行 FastAPI 服务6.3 为什么先复制 requirements.txt因为 Docker 构建有缓存。如果你这样写COPY . . RUN pip install -r requirements.txt每次改一点代码都可能重新安装依赖。更好的写法是COPY requirements.txt . RUN pip install -r requirements.txt COPY app ./app这样只要requirements.txt不变依赖层可以复用缓存构建更快。7. .dockerignore.dockerignore用来排除不需要打进镜像的文件。推荐__pycache__/ *.pyc *.pyo *.pyd .env .venv/ venv/ .git/ .gitignore .pytest_cache/ .mypy_cache/ .ruff_cache/ logs/* data/chroma_db/* data/raw_pdfs/* data/notes/* *.sqlite3 *.db .DS_Store7.1 为什么不把 .env 打进镜像因为.env里可能有OPENAI_API_KEY LANGSMITH_API_KEY DATABASE_URL这些属于敏感配置不应该写进镜像也不应该提交到 Git。正确做法是.env.example 提交到仓库 .env 本地自己创建不提交8. requirements.txt 示例你的项目可能需要fastapi0.115.0 uvicorn[standard]0.30.6 pydantic2.9.2 python-dotenv1.0.1 openai1.52.0 langchain0.3.4 langchain-openai0.2.3 langgraph0.2.39 chromadb0.5.15 pypdf5.0.1 pymupdf1.24.11 sqlalchemy2.0.36 aiosqlite0.20.0 tenacity9.0.0 httpx0.27.2 pytest8.3.3注意版本号可以按你的实际环境调整。 不要盲目复制最好用 pip freeze 或 pyproject.toml 固定项目依赖。9. docker compose 基础如果只有一个 FastAPI 服务用docker run可以。但你的项目可能还需要环境变量 数据目录挂载 日志目录挂载 端口映射 未来扩展 Redis / Postgres / 前端所以更推荐用docker compose。9.1 推荐 docker-compose.ymlservices:api:build:context:.dockerfile:Dockerfilecontainer_name:knowledge-agent-apiports:-8000:8000env_file:-.envvolumes:-./data:/app/data-./logs:/app/logsrestart:unless-stopped9.2 每个字段的作用字段作用services定义服务api服务名build.context构建上下文目录dockerfile指定 Dockerfilecontainer_name容器名称ports宿主机端口:容器端口env_file从.env加载环境变量volumes挂载本地目录restart容器异常退出后的重启策略9.3 启动命令dockercompose up--build后台启动dockercompose up-d--build查看日志dockercompose logs-fapi停止服务dockercompose down重新构建dockercompose build --no-cache10. 环境变量管理环境变量用于把配置从代码里分离出来。10.1 .env.example# App APP_NAMEKnowledge Agent Assistant APP_ENVdevelopment LOG_LEVELINFO # Server HOST0.0.0.0 PORT8000 # LLM OPENAI_API_KEYyour_openai_api_key_here OPENAI_MODELgpt-4.1-mini # RAG VECTORSTORE_DIR/app/data/chroma_db RAW_PDF_DIR/app/data/raw_pdfs NOTES_DIR/app/data/notes TOP_K5 # Database DATABASE_URLsqlite:////app/data/app.db # Observability ENABLE_TRACEtrue LANGSMITH_TRACINGfalse LANGSMITH_API_KEYyour_langsmith_api_key_here # Safety MAX_AGENT_STEPS5 TOOL_TIMEOUT_SECONDS5 REQUIRE_CONFIRMATION_FOR_SENSITIVE_TOOLStrue10.2 app/config.pyfrompydantic_settingsimportBaseSettings,SettingsConfigDictclassSettings(BaseSettings):app_name:strKnowledge Agent Assistantapp_env:strdevelopmentlog_level:strINFOopenai_api_key:stropenai_model:strgpt-4.1-minivectorstore_dir:str/app/data/chroma_dbraw_pdf_dir:str/app/data/raw_pdfsnotes_dir:str/app/data/notestop_k:int5database_url:strsqlite:////app/data/app.dbenable_trace:boolTruemax_agent_steps:int5tool_timeout_seconds:int5require_confirmation_for_sensitive_tools:boolTruemodel_configSettingsConfigDict(env_file.env,env_file_encodingutf-8)settingsSettings()10.3 环境变量原则原则说明密钥不写进代码API Key、DB 密码都放环境变量.env不提交 Git只提交.env.example路径可配置data、logs、vectorstore 路径都用环境变量模型可配置不要把模型名写死安全阈值可配置max steps、timeout 等放配置开发和生产分离development / production 使用不同配置11. FastAPI 服务启动方式11.1 本地开发启动uvicorn app.main:app--reload--host0.0.0.0--port8000适合开发阶段。特点代码改动后自动 reload 但不适合生产11.2 容器启动Dockerfile 中CMD [uvicorn, app.main:app, --host, 0.0.0.0, --port, 8000]适合演示和部署。11.3 更正式的生产启动可以考虑gunicorn app.main:app\-kuvicorn.workers.UvicornWorker\--bind0.0.0.0:8000\--workers2但初学阶段不强求。面试可以说当前项目演示阶段使用 Uvicorn 启动 FastAPI 服务如果进入生产环境可以结合 Gunicorn UvicornWorker多 worker 部署并在前面接 Nginx 做反向代理和 HTTPS。12. 本地 Docker 运行流程12.1 第一步复制环境变量文件cp.env.example .env然后修改OPENAI_API_KEY你的真实 key12.2 第二步构建镜像dockerbuild-tknowledge-agent-assistant.12.3 第三步运行容器dockerrun--rm\--nameknowledge-agent-api\-p8000:8000\--env-file .env\-v$(pwd)/data:/app/data\-v$(pwd)/logs:/app/logs\knowledge-agent-assistantWindows PowerShell 可能写法不同docker run--rm--name knowledge-agent-api -p 8000:8000 --env-file.env -v ${PWD}/data:/app/data-v ${PWD}/logs:/app/logs knowledge-agent-assistant12.4 使用 compose 启动dockercompose up--build12.5 测试健康检查curlhttp://localhost:8000/health预期{status:ok}12.6 测试 chat 接口curl-XPOST http://localhost:8000/chat\-HContent-Type: application/json\-d{ user_id: demo_user, thread_id: demo_thread, question: RAG 为什么能减少幻觉, top_k: 5, enable_trace: true }13. 最小 FastAPI health 接口fromfastapiimportFastAPI appFastAPI(titleKnowledge Agent Assistant)app.get(/health)defhealth_check():return{status:ok,service:knowledge-agent-assistant}这个接口很重要因为部署后你要快速判断服务是否启动成功。14. docker compose 扩展版本如果后面要加 Redis可以这样扩展services:api:build:context:.dockerfile:Dockerfilecontainer_name:knowledge-agent-apiports:-8000:8000env_file:-.envvolumes:-./data:/app/data-./logs:/app/logsdepends_on:-redisrestart:unless-stoppedredis:image:redis:7container_name:knowledge-agent-redisports:-6379:6379volumes:-redis_data:/datarestart:unless-stoppedvolumes:redis_data:如果后面要加 Postgres也可以类似扩展。15. 数据持久化你的项目里至少有这些数据要保留PDF 原文件 Chroma 向量库 SQLite 数据库 日志文件 学习笔记所以不能只放在容器内部。因为容器删除后容器内部文件可能丢失。正确做法是挂载 volumevolumes:-./data:/app/data-./logs:/app/logs这样容器重启或删除后本地data/和logs/仍然保留。16. 常见 Docker 问题排查16.1 端口被占用错误Bind for 0.0.0.0:8000 failed: port is already allocated处理lsof-i:8000或改 composeports:-8001:800016.2 找不到环境变量错误OPENAI_API_KEY missing处理cp.env.example .env检查dockercompose config16.3 容器启动后立刻退出查看日志dockercompose logs-fapi常见原因依赖安装失败 启动命令写错 main.py 路径不对 环境变量缺失 数据库目录无权限16.4 容器里找不到文件进入容器dockerexec-itknowledge-agent-apibash查看目录ls-al/appls-al/app/data16.5 修改代码后没生效重新构建dockercompose up--build或者dockercompose build --no-cache17. 项目一页说明这部分可以保存为docs/project_one_page.md。Knowledge Agent Assistant 项目说明1. 项目背景在论文和技术文档学习场景中用户经常需要从大量 PDF、技术笔记和项目文档中快速定位信息。普通大模型无法直接访问私有知识库容易产生幻觉也不能调用外部工具完成任务。因此我设计了一个带知识库检索、工具调用和多轮状态管理能力的 AI Assistant。2. 技术栈FastAPI提供后端 API 服务Pydantic请求和响应结构校验LangGraph编排 Agent 状态流转Chroma / FAISS向量检索PyMuPDF / pypdfPDF 解析SQLite日志与状态存储Docker / docker compose容器化部署OpenAI API模型调用与生成LangSmith / 自定义 Trace链路观测与评测。3. 系统架构系统分为六层FastAPI 服务层 LangGraph 编排层 RAG 检索层 Tool 工具层 状态存储与日志层 结构化输出层一次请求的流程是用户问题 - FastAPI 参数校验 - LangGraph 初始化 state - 问题分类 - 路由到 RAG / Tool / Direct Answer - 工具结果或检索片段写入 state - 模型生成答案 - 返回 answer、citations、tool_trace、error - 写入日志与 trace4. 核心功能支持 PDF 上传和知识库入库支持基于知识库的 RAG 问答支持外部工具调用支持多轮对话状态支持引用片段返回支持工具调用过程追踪支持错误兜底支持敏感工具确认支持 Docker 一键启动。5. 技术难点难点一普通 RAG 流程不够灵活不是所有问题都应该走检索。解决方案使用 LangGraph 先做问题分类再根据问题类型路由到 RAG、Tool 或直接回答。难点二检索结果不稳定用户问题可能口语化检索结果可能不命中。解决方案加入 query rewrite、top-k 控制、metadata filter、引用片段和检索为空兜底。难点三Agent 可能循环失控或误调用工具解决方案设置最大 step、工具白名单、工具风险分级、敏感工具确认、timeout、retry 和 fallback。难点四回答错误难定位解决方案为每次请求生成 trace_id记录分类、检索、工具调用、生成和结构化输出的输入输出与耗时。6. 评估指标回答正确率检索命中率工具成功率平均响应时间p95 响应时间引用覆盖率错误率。7. 优化方向加 hybrid search加 rerank加 citation verifier扩展更多外部工具引入 Redis / Postgres前端展示 trace timeline增加安全红队测试集使用 Gunicorn Nginx 部署生产环境。18. README 推荐结构你的 README 应该至少包括# Knowledge Agent Assistant ## 项目背景 ## 核心功能 ## 技术栈 ## 系统架构 ## 快速启动 ### 本地启动 ### Docker 启动 ## API 示例 ## Agent 工作流 ## RAG 设计 ## Tool Calling 设计 ## Tracing 与 Evals ## 安全策略 ## 项目难点 ## 后续优化18.1 README 快速启动模板## 快速启动 ### 1. 克隆项目 bash git clone your-repo-url cd knowledge-agent-assistant2. 配置环境变量cp.env.example .env修改.envOPENAI_API_KEYyour_api_key3. Docker 启动dockercompose up--build4. 健康检查curlhttp://localhost:8000/health5. 调用 Chat APIcurl-XPOST http://localhost:8000/chat\-HContent-Type: application/json\-d{ user_id: demo_user, thread_id: demo_thread, question: RAG 为什么能减少幻觉 }--- ## 19. 面试 3 分钟项目介绍稿 这一版可以直接背。 我做的是一个面向论文和技术文档场景的 Knowledge Agent Assistant。最初它是一个普通 RAG 项目用户提问后系统从 PDF 知识库中检索相关 chunk再把检索结果交给模型生成答案。后来我把它升级成了一个 Agent 系统因为真实场景里的问题不只是知识问答有些问题需要查文档元信息有些需要调用工具保存学习笔记有些还依赖多轮上下文。 架构上我把系统分成六层。第一层是 FastAPI 服务层负责接收请求、参数校验和返回结构化响应第二层是 LangGraph 编排层负责维护 state并通过节点和条件边完成问题分类、路由、检索、工具调用和回答生成第三层是 RAG 检索层负责 PDF 解析、chunk 切分、embedding 入库和 top-k 检索第四层是 Tool 层把知识库检索、文档元信息查询、笔记保存等能力封装成工具第五层是状态存储和日志层用 SQLite 和 trace_id 记录多轮状态、工具调用和延迟第六层是结构化输出层统一返回 answer、citations、tool_trace 和 error。 项目的核心流程是用户发起问题后系统先判断问题类型。如果是知识类问题就走 RAG 检索如果是外部任务就走工具调用如果是追问就结合 thread_id 下的历史状态。最终模型基于检索片段或工具结果生成答案并返回引用来源和工具调用过程。 这个项目的难点主要有三个。第一是检索质量不稳定所以我做了 query rewrite、top-k 控制、引用片段和检索为空兜底第二是 Agent 工具调用可能失控所以我加了最大 step、工具白名单、敏感工具确认、timeout 和 fallback第三是回答出错后很难定位所以我加了 tracing记录分类、路由、检索、工具调用和生成每一步的输入输出与耗时。 评估方面我定义了回答正确率、检索命中率、工具成功率和平均响应时间四个核心指标。这样如果答案错了我可以通过 trace 判断是检索没命中、工具失败还是模型没有正确使用证据。 最后我用 Dockerfile 和 docker compose 对项目做了容器化封装把 API 服务、环境变量、数据目录和日志目录统一管理。这样项目不依赖本机环境只需要配置 .env然后执行 docker compose up --build 就可以运行。整体来说这个项目体现了从 RAG 到 Agent再到观测、评测、安全和部署的完整工程链路。 --- ## 20. 面试讲项目时不要跑偏 面试项目介绍常见问题是讲太散。 你应该固定按这个顺序讲 text 1. 项目背景为什么做 2. 系统架构分几层 3. 核心流程一次请求怎么走 4. 关键难点你解决了什么问题 5. 评估指标怎么证明有效 6. 部署方式怎么运行和交付不要一上来讲我用了 FastAPI、LangGraph、Chroma、Docker……这会变成技术名词堆砌。更好的开头是这个项目解决的是私有文档知识库问答和外部工具调用的问题。 普通 RAG 只能固定检索回答我把它升级成了一个可控 Agent。21. 面试高频追问与回答Q1为什么要用 Docker回答Docker 可以把代码、依赖、运行环境和启动命令打包成镜像解决“本地能跑别人跑不了”的问题。我的项目依赖 FastAPI、LangGraph、Chroma、PDF 解析库、SQLite 和环境变量配置Docker 化后可以通过 docker compose 一键启动方便演示和交付。Q2Dockerfile 做了什么回答Dockerfile 定义了服务镜像的构建过程。我使用 Python slim 镜像作为基础镜像设置工作目录安装系统依赖和 Python 依赖复制 app 代码暴露 8000 端口最后用 Uvicorn 启动 FastAPI 服务。Q3docker compose 有什么用回答docker compose 用来编排服务配置。即使当前只有一个 API 服务也可以统一管理端口映射、环境变量、数据目录挂载、日志目录挂载和重启策略。后续如果加 Redis、Postgres 或前端也可以在同一个 compose 文件中扩展。Q4为什么要挂载 data 和 logs回答因为容器本身是临时运行环境删除容器后内部文件可能丢失。我的项目中 PDF 文件、Chroma 向量库、SQLite 数据库和日志都需要持久化所以把本地data/和logs/挂载到容器的/app/data和/app/logs。Q5环境变量怎么管理回答我用.env.example说明需要哪些配置比如 OPENAI_API_KEY、模型名、向量库目录、数据库地址、最大 step、工具超时时间等。真实.env不提交 Git运行时通过 docker compose 的env_file注入容器。这样可以避免把密钥写进代码或镜像。Q6如果服务启动失败怎么排查回答首先用docker compose logs -f api查看启动日志然后检查.env是否配置、端口是否冲突、依赖是否安装成功、FastAPI 入口路径是否正确、data/logs 目录是否挂载。如果容器已启动但接口不通我会先访问/health再检查端口映射和服务监听地址是否是0.0.0.0。Q7你这个项目怎么上线回答当前阶段我完成的是容器化交付可以在任意安装 Docker 的机器上通过 docker compose 启动。如果要正式上线可以把镜像推送到镜像仓库在云服务器上拉取镜像运行前面接 Nginx 做反向代理和 HTTPS再把数据库和向量库的数据目录挂载到持久化磁盘。更进一步可以用 CI/CD 自动构建和发布镜像。Q8生产环境和本地开发有什么区别回答本地开发可以用 Uvicorn 的 reload 模式方便改代码生产环境不能用 reload应该使用稳定的启动方式比如 Gunicorn UvicornWorker并配置日志、超时、健康检查、反向代理和监控。另外生产环境的.env、数据库、向量库路径和密钥管理也应该和开发环境分开。