智能教学平台开发日志 — Tool Calling 接入与项目工程化
今日工作内容
教学平台的 AI Agent 从「手动拼上下文」进化为「LLM 自主决策的 Tool Calling」模式,同时补齐了 Docker 容器化、单元测试、压测等工程化工作。
遇到的坑与解决方案
1. LangChain4j 1.13.0 OpenAiChatModel 的 HTTP 客户端 BUG
现象:调用 OpenAiChatModel.chat() 时抛出 Invalid HTTP method。
原因:LangChain4j 1.13.0 的 OpenAiChatModel 内部使用 JdkHttpClient 发送非流式请求,但在 Java 21 + Spring Boot 4 环境下存在兼容性问题,HTTP 方法无法正常设置。
解决:弃用 OpenAiChatModel,直接用已有的 RestClient 手工实现 tool_calls 循环。核心改动:
1 | // 手工实现 tool_calls 循环,不依赖 OpenAiChatModel |
启示:框架的 HTTP 客户端层不一定可靠,业务层直接使用 Spring RestClient 反而更可控。
2. Tool 参数需要 classId 但 LLM 不知道
现象:LLM 调用 queryStudentStats(studentName, classId) 时不知道 classId 该传多少,胡乱传值导致查不到数据。
解决:所有对外暴露的工具方法改为接受自然语言参数(学生姓名、班级名称),内部通过 classService.getClassByName() 和 submissionMapper.selectList(Wrapper) 完成名称到 ID 的映射。
1 |
|
3. 新增 Controller 导致接口混乱
现象:先新建了 AgentChatController 放 Tool Calling 接口,导致 /api/agent/chat 和原有的 /api/chat/stream 功能重叠,前端不知道该调哪个。
解决:删掉 AgentChatController,直接在 ChatController 的 stream 接口里注入 EduAITools,让前端零改动。
教训:功能迭代尽量在原有代码上扩充,新建 Controller 之前先确认是否真的需要。
4. 连续三次出现 Agent 对话
现象:doChatWithTools 每轮 tool_calls 发一次 POST,造成 Gateway 侧看到多个对话。
解析:这是正常行为——第一次 POST 触发 LLM 返回 tool_calls,第二次 POST 回传工具结果得到最终回答。2-3 轮都合理。
5. JMeter 中文编码导致 XML 加载失败
现象:JMeter testname 属性中的中文字符经过 PowerShell Set-Content 处理后编码损坏,JMeter 报 XmlPullParserException。
解决:所有 testname 改为纯英文,用 (Get-Content -Raw) -replace | Set-Content -Encoding UTF8 确保编码一致性。
技术决策与架构
Tool Calling 数据流
1 | 用户消息 → ChatController.streamMessage() |
当前接口一览
1 | GET /api/chat/health 健康检查 |
工具列表
| 工具 | 类型 | 数据源 | 输入 |
|---|---|---|---|
searchKnowledgeBase |
RAG | document_chunk 表 + pgvector |
关键词 |
queryStudentStats |
数据库查询 | submission 表 |
学生姓名 |
queryClassLearningStatus |
数据库查询 | submission + homework_evaluation + submission_errors 表 |
班级名称 |
queryHomeworkTasks |
数据库查询 | homework_task 表 |
班级名称 |
getCurrentTime |
系统工具 | — | 无 |
后续需要做的事情
P0(面试必问)
- Docker 多阶段构建:Dockerfile + docker-compose.yml 已写好,安装 Docker Desktop 后即可一键部署
- 单元测试:已有 11 个测试覆盖工具层和 AI 编排层,剩余
searchKnowledgeBase、getCurrentTime和 Controller 层待补
P1(建议补齐)
- Metrics 监控:Actuator + Micrometer 自定义指标(AI 批改次数/耗时、Tool Calling 成功率)
- Prompt 外置:把批改 Prompt 和工具描述从代码中移到
config/prompts/目录,支持热加载
P2(锦上添花)
- CI/CD:
.github/workflows/maven.yml自动构建 + 单元测试 - LLM Token 追踪:每次 LLM 调用记录 Token 消耗,控制成本
- JMeter 压测数据:已写好
load-test.jmx,跑完后将缓存加速比和限流准确率写入文档
压测数据
1 | 缓存对比:第一次 83ms → 第二次 8ms(Caffeine 缓存,加速 10 倍) |
备注
application.properties已改为环境变量模式:${DB_HOST:localhost}默认本机,容器化时通过环境变量覆盖- 如需启动 Docker:
docker compose up -d(需先安装 Docker Desktop) - 启动前确保 OpenClaw Gateway(
:18789)和 OneBot(:3000)在宿主机运行





