从零开始做一个 AI Agent:以 Java Web RAG 学习助手为例
本文是一套面向技术博客专栏的完整教程。它不是只讲概念,而是以当前项目为真实案例,从一个最小后端 API 出发,逐步扩展到课程资料知识库、RAG 问答、轻量级 Agent Harness、工具注册表、执行 Trace、答案校验、学习记忆和前端工作台。
示例项目定位:
面向 Java Web 课程资料的 RAG Agent 学习助手用户可以上传课程课件、实验指导书、代码文件和配置文件。系统会解析资料、切块、建立检索索引;用户提交学习任务后,Agent 会判断任务类型、规划步骤、调用工具、生成回答、校验引用,并把执行过程展示给前端。
专栏总目录
- 项目总览:从普通问答到课程学习 Agent
- 技术栈和工程结构:FastAPI、Vue、SQLite、RAG、Agent Harness
- 后端基础设施:配置、数据库、模型和 Schema
- 资料上传:文件存储、文档记录和重建索引
- 文档解析:PDF、Word、PPT、Markdown、代码文件如何进入系统
- 文本切块:chunk、metadata、语义类型和 embedding 状态
- 检索系统:关键词检索、向量检索、query rewrite 和 rerank
- LLM 与 Embedding Provider:stub、OpenAI-compatible API 和本地模型接入
- Chat 问答入口:兼容普通问答,同时接入 Agent 主链路
- Agent Harness:一次 Agent run 的生命周期
- Planner、Executor 与 Tool Registry:Agent 如何规划和调用工具
- Agent 校验、安全边界与资料不足处理
- Agent 记忆:短期上下文、长期学习画像和推荐下一步
- 前端工作台:资料管理、Agent 任务、Trace、历史和健康状态
- 测试、局限和演进:从教学项目走向生产级 Agent SaaS
第 6 篇:文本切块:chunk、metadata、语义类型和 embedding 状态
6.1 为什么要 chunk
大文档不能直接进入检索和 Prompt。chunk 的作用是:
控制单段长度 保留来源信息 支持局部检索 支持局部引用 支持 embedding6.2 切块入口
文件:
backend/app/services/chunking.py入口函数:
defchunk_parsed_document(parsed:ParsedDocument,max_chars:int=900,overlap_chars:int=120,)->list[ChunkData]:默认策略:
每块最大 900 字符 相邻块重叠 120 字符重叠的意义是避免知识点刚好被切断。
6.3 ChunkData 结构
@dataclass(frozen=True)classChunkData:content:strchunk_type:strsource_title:strsource_path:strsource_page:int|Nonelanguage:str|Nonemetadata:dict[str,Any]这些字段最终会写入chunks表。
6.4 LLM metadata enrichment
每个 chunk 会尝试调用 LLM 生成元数据:
semantic_type entities summary允许的 semantic_type:
concept lab_step code error exam_hint configuration general如果 LLM 不可用,系统会兜底:
代码 chunk -> semantic_type = code 其他 chunk -> semantic_type = general这体现了项目的稳定性原则:LLM 增强可以失败,但核心入库流程不能因为 LLM 不可用就完全不可用。
6.5 文档入库状态流转
文件:
backend/app/services/ingestion.py状态流转:
uploaded -> processing -> chunked -> indexed失败时:
failed + error_message入库流程会先删除旧 chunks,再写入新 chunks,避免 reindex 后出现重复数据。