项目整体流程图

AI Agent 工程实践教程 · 第 06 章

用流程图拆解课程项目的用户入口、Agent 编排、知识库和业务服务边界。

返回系列目录

第六天补充:学生端 AI 问答项目整体地图

前面几天我们已经分别学习了大模型调用、RAG、LlamaIndex、提示词和工具调用。

但是如果只看单个文件,很容易觉得每一块都是零散的。

这一节先不急着学习新的 API。

我们先把整个 AI 问答项目串起来,看清楚下面几个问题:

学生前端怎么发起 AI 问答?
Java 后端为什么要参与?
Python AI 服务到底负责什么?
知识库资料怎么入库?
聊天时怎么决定要不要查知识库?
工具调用为什么还要回到 Java?
哪些数据存在 MySQL,哪些数据存在 Milvus?

用流程图串起来以后,我们会发现:

前端、Java、Python、Milvus、大模型不是孤立的。
它们共同组成了一个完整的 AI 问答系统。

0. 先看两张主线图

完整项目图信息比较多,一开始直接看会有点乱。

所以我们先看两张主线图。

第一张图先说明:

这个项目其实分成两条线。

第一条线:管理端准备线。
第二条线:学生端运行线。

AI 问答项目先分成两条线

0.1 第一条线:管理端准备线

管理端准备线是:

知识库资料和提示词先准备好。

这条线可以分成 5 步:

1. 管理员维护知识库。
2. 管理员上传 Markdown 文档。
3. Java 调 Python 做文档入库。
4. Python 切块、向量化、写入 Milvus。
5. 管理员维护提示词,并发布当前生效版本。

这一条线不是学生提问时才发生的。

它更像是“正式运行前的准备”:

资料先进知识库,规则先进提示词中心。

只有准备好了这些内容,后面学生提问时,AI 才有资料可查、有规则可遵守。

0.2 第二条线:学生端运行线

学生端运行线是:

学生真正问一句话时,系统怎么完成一次 AI 回答。

这条线可以分成 6 步:

1. 学生在前端输入问题。
2. Java 做学生鉴权、会话校验、历史查询和消息落库。
3. Java 把请求转发给 Python。
4. Python 做 RAG、提示词、工具和模型编排。
5. Python 调模型流式生成回答。
6. Java 把流式结果转发给前端,并保存完整 AI 回答。

先理解这两条线,后面再看细节图就不会乱。


0.3 一次问答流程

接下来再看一次完整问答。

也就是:学生点“发送”以后,到底发生了什么。

学生端一次 AI 问答,按 12 步看懂

这 12 步是整条运行链路:

1. 前端发送问题。
2. Java 校验当前学生和会话归属。
3. Java 查询当前会话最近历史消息。
4. Java 先保存学生本次问题。
5. Java 调 Python 的流式 AI 接口。
6. Python 从 Java 提示词中心读取当前生效提示词。
7. Python 判断本次问题要不要查知识库。
8. Python 组装 messages。
9. Python 判断本次问题要不要开放工具。
10. Python 调大模型并以 SSE 输出 chunk。
11. Java 转发 chunk,前端逐段显示。
12. done 后 Java 保存完整 AI 回答,前端刷新消息。

看完这两张清晰版图以后,后面再展开细节:

项目总架构图:各系统分别负责什么。
管理端配置图:知识库和提示词接口怎么工作。
Python 决策图:RAG、Prompt、Tool 怎么分支。
知识库入库图:文档怎么变成向量。
工具调用图:课表工具怎么查真实业务数据。
数据配置图:哪些数据存在哪里。

1. 项目总架构

学生端 AI 问答项目总架构

这张图说明系统分工。

1.1 学生前端负责什么

学生前端在:

YanQue-Student-Web

核心页面是:

YanQue-Student-Web/src/pages/StudentAiChatPage.tsx

它主要负责:

  1. 展示会话列表。
  2. 展示当前会话消息。
  3. 发送学生输入的问题。
  4. 接收流式返回的 AI 回答。
  5. chunk 逐段追加到页面上。
  6. done 后重新加载数据库里的完整消息。

前端不负责:

  1. 学生身份校验。
  2. 历史消息查询。
  3. 知识库检索。
  4. 工具调用。
  5. 调大模型。

这些都在后端完成。

1.2 Java 后端负责什么

Java 后端在:

YanQue-Admin

学生端 AI 问答入口是:

cn.yanque.studentFront.controller.StudentAiChatController

核心业务类是:

cn.yanque.studentFront.biz.impl.StudentAiChatBizImpl
cn.yanque.studentFront.service.impl.ai.StudentAiChatServiceImpl
cn.yanque.studentFront.client.ai.PythonAiChatClient

Java 负责:

  1. 校验当前学生身份。
  2. 校验会话是否属于当前学生。
  3. 创建、查询、删除 AI 会话。
  4. 保存学生消息。
  5. 查询最近历史消息。
  6. 调用 Python AI 服务。
  7. 解析 Python 返回的 SSE。
  8. 把 SSE 再转发给前端。
  9. 保存 AI 完整回答。
  10. 给 Python 提供内部工具接口和提示词接口。

也就是说:

Java 是业务中枢。

它不直接负责模型推理,但它负责业务安全和数据落库。

1.3 Python AI 服务负责什么

Python AI 服务在:

YanQue-AI

核心入口是:

yanque_ai/api/chat_api.py

核心编排类是:

yanque_ai/chat/service.py

Python 负责:

  1. 接收 Java 传来的聊天请求。
  2. 判断是否需要知识库。
  3. 需要时调用 LlamaIndex/Milvus 检索资料。
  4. 从 Java 提示词中心读取当前生效提示词。
  5. 组装模型 messages
  6. 判断本轮是否需要开放工具。
  7. 需要工具时执行工具调用流程。
  8. 调用百炼大模型。
  9. 以 SSE 格式把回答流式返回给 Java。

也就是说:

Python 是 AI 编排层。

它负责把知识库、提示词、历史消息、工具和大模型组织起来。

1.4 外部和存储负责什么

外部和存储主要包括:

  1. MySQL:保存业务数据、会话消息、提示词、知识库文档记录。
  2. TOS:保存上传的 Markdown 文档。
  3. Milvus:保存知识库 chunk 的向量和元数据。
  4. 百炼 Chat 模型:生成回答、做知识库路由、做工具决策。
  5. 百炼 Embedding 模型:把文档和问题转成向量。

2. 管理端 AI 能力配置流程

管理端 AI 能力配置流程:知识库、检索、提示词

这张图专门补充“后台管理端做了哪些 AI 配置”。

学生端 AI 问答能正常回答,不只是因为聊天接口能跑。

它前面还有三类管理能力:

知识库管理
知识库检索验证
提示词管理

这三类能力都在管理端前端:

YanQue-Admin-Web

对应页面:

KnowledgeBasesPage.tsx
KnowledgeSearchPage.tsx
PromptTemplatesPage.tsx

对应前端 API 封装在:

YanQue-Admin-Web/src/api/system.ts

2.1 知识库管理接口

知识库管理入口是:

KnowledgeBaseController

基础路径:

/api/knowledgeBases

主要接口:

接口 作用
POST /api/knowledgeBases 新增知识库
PUT /api/knowledgeBases/{id} 修改知识库
DELETE /api/knowledgeBases/{id} 删除知识库
GET /api/knowledgeBases/{id} 查询知识库详情
GET /api/knowledgeBases 分页查询知识库

这部分只管理知识库的基础信息。

比如:

知识库名称
知识库编码或描述
状态
创建时间
更新时间

真正的文档入库不在这里完成,而是在文档接口里完成。

2.2 知识库文档接口

知识库文档管理入口是:

KnowledgeDocumentController

它的接口分布在:

/api/knowledgeBases/{knowledgeBaseId}/documents
/api/knowledgeDocuments/{id}

主要接口:

接口 作用
GET /api/knowledgeBases/{knowledgeBaseId}/documents 分页查询某个知识库下的文档
POST /api/knowledgeBases/{knowledgeBaseId}/documents/index 上传知识库文档并入库
POST /api/knowledgeDocuments/{id}/reindex 重新入库某个文档
GET /api/knowledgeDocuments/{id}/download-url 获取文档下载预签名
GET /api/knowledgeDocuments/{id}/chunks 查询文档切块明细
DELETE /api/knowledgeDocuments/{id} 删除文档记录

这里要注意:

Java 管文档记录和入库状态;
Python 负责真正下载 Markdown、切块、向量化、写 Milvus。

当管理员点击“上传并入库”时,Java 会:

  1. 创建文档记录。
  2. 标记文档 INDEXING
  3. 生成 TOS 预签名下载地址。
  4. 调 Python 知识库入库接口。
  5. Python 返回 chunk 数和向量维度。
  6. Java 标记文档 INDEXEDFAILED

文档状态在前端可以展示为:

PENDING
INDEXING
INDEXED
FAILED

这样管理员能知道文档是否已经可以被 AI 检索使用。

2.3 知识库检索接口

管理端还有一个单独的知识库检索页面。

入口是:

KnowledgeSearchController

接口是:

POST /api/knowledgeSearch/search

它的作用不是学生聊天,而是给管理员测试知识库检索效果。

比如管理员可以输入:

RAG 课程讲了什么?

然后查看:

  1. 命中了哪些文档。
  2. 命中了哪些 chunk。
  3. 相似度分数是多少。
  4. 返回内容是否符合预期。

这个页面很重要。

因为 RAG 效果不好时,不一定是大模型的问题。

也可能是:

  1. 文档没有入库成功。
  2. 文档切块不合适。
  3. embedding 模型不一致。
  4. topK 太少。
  5. 查询问题没有召回正确 chunk。

所以管理端检索页面相当于一个“知识库调试工具”。

2.4 提示词管理接口

提示词管理入口是:

PromptTemplateController

基础路径:

/api/promptTemplates

它管理两层数据:

提示词模板
提示词版本

提示词模板表示一个稳定的业务用途。

比如:

ai_chat_system
ai_chat_knowledge_router
ai_chat_tool_router

提示词版本表示这个用途下面的具体内容。

主要接口:

接口 作用
POST /api/promptTemplates 新增提示词,并创建第一个版本
PUT /api/promptTemplates/{id} 修改提示词基础信息
DELETE /api/promptTemplates/{id} 删除提示词
GET /api/promptTemplates/{id} 查询提示词详情
GET /api/promptTemplates 分页查询提示词
GET /api/promptTemplates/{templateId}/versions 查询提示词版本列表
POST /api/promptTemplates/{templateId}/versions 新增提示词版本
PUT /api/promptTemplates/versions/{versionId} 修改提示词版本
DELETE /api/promptTemplates/versions/{versionId} 删除提示词版本
POST /api/promptTemplates/versions/{versionId}/publish 发布或回滚提示词版本

这里要重点讲“发布”的意义。

提示词不是写死在 Python 代码里的。

后台可以维护多个版本:

V1:回答比较简洁
V2:回答更适合学生
V3:增加知识库边界要求

当前真正被 Python 使用的是:

activeVersionId 指向的版本

发布或回滚版本时,不需要重新部署 Python。

2.5 Python 怎么读取当前生效提示词

Python 运行时不会直接查 Java 数据库。

它会调用 Java 内部接口:

InternalPromptController

接口:

GET /internal/ai/prompts/active?code=提示词编码

这个接口会校验:

X-Internal-Token

如果本地开发没配置 token,只允许本机回环地址访问。

Python 侧读取提示词的位置是:

yanque_ai/chat/prompt_client.py

核心类:

JavaPromptClient

它的逻辑是:

  1. 先看本地短时缓存有没有未过期内容。
  2. 没有缓存就调用 Java 内部接口。
  3. Java 返回当前生效版本内容。
  4. Python 缓存一小段时间。
  5. Java 临时不可用时,优先使用旧缓存。
  6. 旧缓存也没有时,使用 Python 默认 fallback。

这个设计的好处是:

后台可以发布提示词;
Python 不需要每次请求都打 Java;
Java 短暂异常时不影响学生正常提问。

2.6 提示词管理和聊天链路的关系

聊天时会用到多类提示词。

比如:

提示词 用途
AI 聊天系统提示词 规定 AI 问答助手身份、回答风格、边界
知识库路由提示词 判断本轮问题是否需要查知识库
工具路由提示词 判断本轮问题应该开放哪些工具

所以提示词管理不是后台的“装饰功能”。

它直接影响:

  1. AI 回答风格。
  2. 知识库使用策略。
  3. 工具调用策略。
  4. 线上问题回滚能力。

如果某个提示词效果不好,可以在后台新增版本并发布。

如果新版本效果变差,也可以发布旧版本完成回滚。


3. 学生发送一条 AI 消息的完整时序

学生发送一条 AI 消息的完整时序

这张图说明:学生问一句话以后,系统到底发生了什么。

2.1 前端先创建临时消息

学生在页面输入问题后,前端会先做两件事:

  1. 创建一条临时 user 消息。
  2. 创建一条空的 assistant 消息。

这样页面可以马上显示学生刚发的问题,并预留一个 AI 回答区域。

核心位置:

StudentAiChatPage.tsx

前端调用:

studentApi.streamAiChatMessage(sessionId, content, onEvent)

对应接口:

POST /student/ai-chat/sessions/{sessionId}/messages/stream

2.2 Java 接收请求并构造 Python 请求

Java 入口:

StudentAiChatController.streamMessage

真正业务在:

StudentAiChatBizImpl.streamMessage

它会先拿当前学生:

StudentThreadLocal.get()

然后构造发给 Python 的请求:

studentId
sessionId
message
promptCode
history

其中 history 来自:

StudentAiChatServiceImpl.buildRecentHistory

它会查询当前会话最近 N 条历史消息。

这里有一个顺序要特别讲:

Java 是先构造 Python 请求,再保存 user 消息。

这样传给 Python 的历史消息不会重复包含本次问题。

本次问题单独放在:

message

Python 组装 messages 时会把它放到最后。

2.3 Java 先保存用户消息

在调用 Python 之前,Java 会保存学生本次问题:

studentAiChatService.saveUserMessage(studentId, sessionId, message)

保存到:

ai_chat_message

角色是:

role = user

同时会更新会话:

  1. 如果会话标题为空,用用户问题截取前 30 个字符作为标题。
  2. 更新会话 updatedAt

2.4 Java 异步调用 Python

Java 会创建:

SseEmitter

然后用:

CompletableFuture.runAsync(...)

异步执行:

PythonAiChatClient.streamChat(...)

这里为什么要异步?

因为 AI 回答是长连接流式返回。

Java Controller 不能一直阻塞普通返回逻辑,而是要把 SseEmitter 先返回给前端,再由异步线程持续往里面写事件。

2.5 Python 返回 SSE

Python 接口:

POST /api/ai-chat/stream

返回类型:

text/event-stream

事件主要有:

事件 含义
message_start AI 开始回答,返回模型名
chunk 一段增量文本
done 回答完成,返回 token、知识库引用等信息
error AI 服务异常

Java 的:

PythonAiChatClient.readSse

会逐行读取 Python 返回的 SSE。

读到一个完整事件后,分发给:

PythonAiChatStreamHandler

2.6 Java 边读边转发给前端

Java 收到 Python 的 chunk 后:

  1. 追加到 assistantContent
  2. 通过 SseEmitter 发送给前端。

代码位置:

StudentAiChatBizImpl.doStream

核心逻辑:

onChunk(content)
  ↓
assistantContent.append(content)
  ↓
send(emitter, "chunk", ...)

前端收到 chunk 后,把内容追加到当前 AI 消息里。

2.7 done 后保存 AI 完整回答

当 Python 发出 done 事件时,Java 会:

  1. 从 done 里拿模型名和 token。
  2. 把累积好的 assistantContent 保存到数据库。
  3. 给前端转发 done

保存位置:

StudentAiChatServiceImpl.saveAssistantMessage

保存到:

ai_chat_message

角色是:

role = assistant

前端收到 done 后,会重新调用:

GET /student/ai-chat/sessions/{sessionId}/messages

加载数据库里的最终消息。


4. Python AI 服务内部决策流程

Python AI 服务内部决策流程

这张图说明 Python 内部的 AI 编排。

入口是:

yanque_ai/api/chat_api.py

核心方法是:

ChatService.stream_chat

3.1 收到 ChatStreamRequest

Python 收到 Java 传来的请求:

ChatStreamRequest

里面包含:

  1. student_id
  2. session_id
  3. message
  4. history
  5. prompt_code

Python 不再自己判断学生是否登录。

因为学生鉴权已经在 Java 完成。

Python 只把 student_id 当成工具调用时的业务上下文。

3.2 先做 RAG 检索

Python 会先执行:

rag_result = self._retrieve_rag_context(request)

如果没有配置默认知识库:

ai_chat_default_knowledge_base_id

就直接不查知识库。

如果配置了默认知识库,就进入:

ChatRagService.retrieve

3.3 知识库路由

知识库不是每个问题都查。

先由:

ChatKnowledgeRouter.should_use_knowledge

判断本轮要不要查知识库。

判断顺序是:

  1. 如果配置了强制开关,直接使用配置结果。
  2. 如果命中课程、作业、讲义、制度、价格等关键词,直接使用知识库。
  3. 否则调用轻量模型,让模型返回 JSON 判断结果。
  4. 如果模型判断失败,保守使用知识库。

这里可以讲一个设计思想:

内部资料类问题,宁可多查知识库,也不要让模型纯猜。

3.4 知识库检索

如果路由结果是需要知识库:

KnowledgeService.search

会调用:

KnowledgeVectorStore.search

最终通过:

LlamaIndex VectorStoreIndex.from_vector_store
retriever.retrieve(question)

从 Milvus 查出相似 chunk。

检索结果会被转换成:

KnowledgeSearchHit

后面放进 Prompt。

3.5 读取提示词中心

Python 不直接使用写死的系统提示词。

它会用:

JavaPromptClient.get_active_prompt_content(request.prompt_code)

去 Java 提示词中心拿当前生效版本。

如果 Java 暂时不可用,才回退到 Python 默认配置。

这样做的好处是:

提示词可以在后台发布和回滚,不需要重新发 Python 服务。

3.6 组装 messages

组装位置:

ChatPromptBuilder.build

顺序是:

1. system:系统提示词
2. system:知识库资料,如果有
3. history:历史消息
4. user:本次学生问题

这个顺序很重要。

因为模型会按 messages 顺序理解上下文。

3.7 判断是否开放工具

接着 Python 判断工具调用是否开启:

ai_chat_tools_enabled

如果开启,就用:

ToolChatAgent.select_tool_definitions

根据本轮问题筛选候选工具。

如果没有候选工具:

直接走 llm_provider.stream_chat(messages)

如果有候选工具:

走 tool_agent.stream(...)

3.8 最终统一输出

无论是普通模型回答,还是工具回答,最后都会回到:

_stream_agent_response

它负责:

  1. 把模型文本 chunk 逐段 yield 出去。
  2. 缓存 usage token。
  3. 最后发送 done payload。

done 里包括:

  1. model
  2. tokens
  3. knowledgeUsed
  4. knowledgeRouteReason
  5. knowledgeReferences

5. 知识库文档入库完整流程

知识库文档入库完整流程

这张图说明:知识库不是聊天时才出现的,它前面还有一个资料入库流程。

4.1 管理端上传文档

管理员先在后台上传 Markdown 文档。

文件实际存储在:

TOS

Java 保存文档对象信息:

objectKey
fileSize
documentName
version

4.2 Java 创建文档记录

入库入口在知识库模块:

KnowledgeDocumentBizImpl.index

Java 会先创建一条文档记录:

knowledgeDocumentService.createPending(...)

状态类似:

PENDING

4.3 标记入库中

真正执行入库前,Java 会标记:

markIndexing(documentId)

这样前端可以看到文档正在入库。

4.4 生成预签名下载地址

Java 不把本地文件路径传给 Python。

而是通过:

UploadService.createDownloadPresign(objectKey)

生成一个临时下载地址。

然后把这个地址传给 Python。

这样设计有两个好处:

  1. Python 不需要直接知道 TOS AK/SK。
  2. Python 不依赖 Java 服务器本地文件路径。

4.5 Python 下载 Markdown

Python 接到入库请求后:

KnowledgeService.index_markdown_document

先用:

KnowledgeDocumentLoader.load_markdown

从预签名地址下载 Markdown 内容。

4.6 Python 切块

下载后用:

KnowledgeChunker.split_markdown

把 Markdown 切成多个 Node。

每个 Node 会带 metadata。

比如:

  1. knowledge_base_id
  2. document_id
  3. document_name
  4. chunk_index
  5. version
  6. source

4.7 写入 Milvus

写入位置:

KnowledgeVectorStore.replace_document

它会:

  1. 根据 knowledgeBaseId 构造 Milvus Collection 名。
  2. 如果同一文档已经入库过,先删除旧 chunk。
  3. 用 LlamaIndex 的 VectorStoreIndex 写入新 nodes。
  4. 用百炼 embedding 模型生成向量。
  5. 把文本、向量、metadata 保存到 Milvus。

这里要强调:

一个知识库对应一个 Milvus Collection。

所以查询某个知识库时,直接连接对应 Collection。

4.8 Java 更新入库结果

Python 返回:

chunkCount
vectorDim
collectionName

Java 收到后标记:

markIndexed(documentId, chunkCount, vectorDim)

如果入库失败:

markFailed(documentId, errorMessage)

6. 工具调用详细流程

工具调用详细流程

这张图说明:AI 为什么能查真实课表。

以学生问:

我今天上什么课?

为例。

5.1 先判断有没有工具候选

Python 先看工具总开关:

ai_chat_tools_enabled

如果关闭,直接普通问答。

如果开启,就进入工具路由:

ChatToolRouter.route

工具路由器根据问题,从工具注册表中选择本轮可以开放的工具。

目前注册的工具包括:

  1. get_student_day_schedule
  2. get_day_duty

5.2 给模型传工具 schema

如果本轮问题适合查课表,Python 会把工具 definition 交给模型。

课表工具定义在:

StudentDayScheduleTool.definition

核心参数只有:

date

没有:

studentId
classId

这是非常重要的安全设计。

5.3 工具决策模型只负责 tool_call

第一次模型调用不是最终回答。

它只负责:

判断要不要调用工具,以及工具参数怎么填。

比如模型可能返回:

{
  "name": "get_student_day_schedule",
  "arguments": {
    "date": "2026-07-07"
  }
}

5.4 Python 执行工具

模型不会真的查数据库。

真正执行工具的是 Python 程序:

ChatToolRegistry.execute

它会:

  1. 解析模型返回的 tool_call。
  2. 找到对应 ChatTool。
  3. 解析 arguments。
  4. 调用工具对象的 execute

如果工具不存在或参数不是合法 JSON,也不会直接崩。

Registry 会返回一个结构化失败结果,让模型后面可以自然地告诉学生。

5.5 工具回到 Java 查询业务数据

课表工具执行时:

StudentDayScheduleTool.execute

不会直接连业务数据库。

它会通过:

JavaStudentScheduleClient

调用 Java 内部接口:

GET /internal/ai/tools/student-day-schedule

参数是:

studentId:来自 Java 已鉴权上下文
date:来自模型工具参数

内部接口会校验:

X-Internal-Token

如果没有配置 token,本地开发只允许回环地址访问。

5.6 Java 查询课表

Java 工具服务会根据学生 ID 查询真实业务数据:

学生 → 班级 → 日期 → 课表

然后返回结构化结果给 Python。

Python 把工具结果作为 role=tool 消息放回模型上下文。

5.7 第二次模型调用生成最终回答

第二次模型调用不再传 tools。

此时模型只做一件事:

根据工具结果,整理成学生能听懂的自然语言回答。

然后继续流式返回给 Java 和前端。


7. 数据和配置关系

AI 问答相关数据和配置关系

这张图用来总结项目里的数据和配置。

6.1 聊天数据

聊天会话表:

ai_chat_session

主要保存:

  1. 学生 ID。
  2. 会话标题。
  3. 会话状态。
  4. 创建时间。
  5. 更新时间。

聊天消息表:

ai_chat_message

主要保存:

  1. 会话 ID。
  2. 消息角色。
  3. 消息内容。
  4. 模型名。
  5. token 数。
  6. 创建时间。

Java 根据这些数据实现:

  1. 会话列表。
  2. 消息列表。
  3. 历史上下文。
  4. AI 回答落库。

6.2 知识库数据

Java 数据库里保存:

  1. 知识库基础信息。
  2. 文档基础信息。
  3. 文档入库状态。
  4. chunk 数量。
  5. 向量维度。
  6. TOS objectKey。

TOS 保存:

Markdown 原文件

Milvus 保存:

chunk 文本
chunk 向量
metadata

这里要注意:

Java 负责业务记录。
Milvus 负责语义检索。
TOS 负责原文件存储。

6.3 提示词和配置

提示词内容保存在 Java 数据库:

prompt_template
prompt_template_version

Python 通过内部接口读取当前生效提示词。

Python .env 或配置里主要保存:

  1. 百炼 API Key。
  2. 百炼 baseUrl。
  3. 默认模型。
  4. embedding 模型。
  5. 默认知识库 ID。
  6. RAG topK。
  7. 工具开关。
  8. Milvus 连接信息。

Java 配置里主要保存:

  1. Python AI 服务地址。
  2. Python 知识库服务地址。
  3. 内部接口 token。
  4. SSE 超时时间。
  5. 历史消息条数。

6.4 外部模型和业务工具

百炼 Chat 模型负责:

  1. 普通回答。
  2. 知识库路由判断。
  3. 工具路由判断。
  4. 工具决策。
  5. 工具结果总结。

百炼 Embedding 负责:

  1. 文档 chunk 向量化。
  2. 用户问题向量化。

Java 内部工具接口负责:

  1. 查询学生当天课表。
  2. 查询当天值日。
  3. 以后可以继续扩展更多业务工具。

8. 推荐学习顺序

不要一上来就看最复杂的细节图。

可以按下面这个顺序阅读。

第一步:先看两条主线

使用:

project_clear_two_flows.svg

先看懂:

AI 问答项目不是一条线,而是“管理端准备线 + 学生端运行线”。

第二步:再看一次问答 12 步

使用:

project_clear_runtime_steps.svg

看懂:

学生点发送以后,前端、Java、Python、知识库、工具和模型分别在什么时候参与。

第三步:再看总架构

使用:

project_overall_architecture.svg

看懂:

前端、Java、Python、Milvus、百炼各自负责什么。

第四步:看管理端先配置了什么

使用:

project_admin_management_flow.svg

看懂:

知识库、知识库检索验证、提示词版本发布,都是 AI 问答正常运行前的后台配置能力。

第五步:看一条消息怎么跑完

使用:

project_student_chat_sequence.svg

看懂:

用户发一句话,到 AI 回答保存进数据库,中间经过哪些步骤。

第六步:看 Python 为什么是 AI 编排层

使用:

project_python_ai_decision_flow.svg

看懂:

Python 不是简单转发请求,它负责 RAG、提示词、工具和模型的决策编排。

第七步:看知识库从哪里来

使用:

project_knowledge_indexing_flow.svg

看懂:

聊天时能查知识库,是因为前面已经完成了文档入库和向量化。

第八步:看工具调用怎么保证安全

使用:

project_tool_calling_flow.svg

看懂:

模型只负责选择工具和填 date。
studentId 这类权限相关信息必须来自程序上下文。

第九步:看数据和配置

使用:

project_data_config_map.svg

看懂:

哪些数据在 MySQL,哪些在 TOS,哪些在 Milvus,哪些是运行配置。

9. 一句话总复盘

这个项目可以这样总结:

学生前端负责聊天体验;
Java 后端负责学生鉴权、会话消息、业务数据和内部接口;
Python 服务负责 AI 编排;
LlamaIndex 和 Milvus 负责知识库检索;
百炼负责模型生成和 embedding;
工具调用把 AI 和真实业务系统连接起来。

如果用更工程化的话说:

这是一个 Java 业务系统 + Python AI 服务 + 向量数据库 + 大模型服务 共同组成的学生端 AI 问答系统。

第六天讲 LangChain 时,就可以从这里过渡:

现在我们已经知道整个项目流程很复杂。
所以接下来要学 LangChain:
用框架把 Prompt、Model、Parser、RAG、Tool 这些步骤组织成更清楚的 Chain。