Java 默认编译不保留方法参数名。类文件里方法的形参是
arg0、arg1,除非编译时加了-parameters。LangChain4j 靠反射拿到的参数名,把 LLM 返回的 JSON 参数映射回@Tool方法实参。名字拿不到,映射就失败:要么参数是 null 却不报错,要么在 agentic 的 sequential 流程里抛MissingArgumentException。
Issue & Env(案发现场与环境)
- 业务场景:用 LangChain4j 的
@Tool让模型调本地方法。参数名没编译进去,映射失败。 - 症状一(静默):工具方法里参数拿到 null 或默认值,业务结果不对,却一个异常都不抛。
- 症状二(显式):在 agentic 的 sequential 流程里,直接抛
MissingArgumentException。 - 环境:LangChain4j,JDK 17+,Maven 或 Gradle 构建。
StackTrace(堆栈日志)
issue #3746 里的报错原文:
dev.langchain4j.agentic.agent.MissingArgumentException: Missing argument: inputAgentB
异常消息形态就是 Missing argument: <参数名>,参数名随你的代码而变。这个类是 agentic 模块的。纯 @Tool 场景的典型表现不一样:参数拿到 null,但完全不报错,更难查。
Reproduce(复现代码)
一个带参数的 @Tool 方法:
public class MathTools {
@Tool("两个整数相加")
public int add(int a, int b) {
return a + b;
}
}
编译时没加 -parameters。模型按 JSON 键值对传参,比如 {"a":1,"b":2}。LangChain4j 想把名字映射回 a、b,反射却只看到 arg0、arg1,映射不上,两个参数都成了默认值。加法结果自然不对。
Root Cause(根因分析)
Java 默认丢弃参数名
Java 编译默认不保留方法形参名。类文件里方法参数表里是 arg0、arg1。加 -parameters 才会写入真实名字。源码带调试信息 -g 的特定情况另说,这里不展开。
映射偏偏靠这个名字
LangChain4j 把 LLM 返回的工具调用参数(JSON,按名字的键值对)映射回 @Tool 方法实参,靠的就是反射拿到的参数名。名字丢了,映射链就断了。
两种症状,一种更难查
参数名拿不到,映射不上,参数就是 null。静默模式下模型和业务都在猜,谁都不报错。在 agentic 的 sequential 流程里,则会直接抛 MissingArgumentException,反而好定位。
显式命名只能缓解
@V("topic")、@P(name = "...") 这类显式命名能部分缓解。但底层没参数名时依然会出问题。issue #6282 记录了 @P(name) 在某些写入路径下被忽略的情况。
The Fix(解决方案)
1. Maven 加编译参数
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
2. Gradle 加编译参数
Groovy DSL:
tasks.withType(JavaCompile) {
options.compilerArgs << '-parameters'
}
Kotlin DSL:
tasks.withType<JavaCompile> {
options.compilerArgs.add("-parameters")
}
3. Spring Boot 工程最容易踩的地方
用 spring-boot-starter-parent 的工程,它默认已经开了 -parameters。一旦你自己覆盖了 compiler 插件的配置,这个默认就可能丢。重点检查这里,别把默认配置盖没了。
4. IDE 编译的诡异差异
IDE(IDEA「Build project」)默认不加 -parameters。会出现「命令行 mvn 打包正常、IDE 里跑就参数为 null」的差异。同步 IDE 的编译设置,或让 IDE 走 Maven/Gradle 编译。
5. 验证
javap -p -v YourToolClass.class | grep -A2 MethodParameters
能看到真实参数名,说明生效了。
6. 兜底
给 @Tool 方法参数显式命名(@P / @V),并在工具内部对 null 参数做校验。早失败,早发现。
小结
@Tool 参数名丢失,根子在编译期。先给 Java 编译加上 -parameters,再留意 Spring Boot 默认配置被覆盖、IDE 编译不生效这两处坑。实在拿不准,就用 javap 看一眼类文件里到底有没有真实参数名。
References(参考来源)
- Fail fast on parameter name mismatches in sequential agentic system — langchain4j issue #3746github-issue
- @P(name) is ignored when agent arguments are written into the AgenticScope — langchain4j issue #6282github-issue
- Tools — LangChain4j 官方文档langchain4j-docs
- javac 手册(-parameters 选项)— Oracle Java SE 17official-docs
