开源之旅的起点
AI Coding的浪潮汹涌不止,OpenHands最是让我爱不释手,虽不及Copilot, Cursor知名,但技术含量感觉只高不低,给玩家了太多想象空间。OpenHands为AI应用构建提供了出色的框架,特别是在LLM调用和Agent开发上极为便捷。昨晚与一朋友Debug个问题到深夜,一筹莫展之际偶然发现了一个关于max_output_tokens
参数的bug,借此良机完成了第一个PR。
问题发现与复现
在尝试通过OpenHands调用openrouter/anthropic/claude-3.7-sonnet
模型时,我发现当设置max_output_tokens
参数且需要生成较长响应(>4096 tokens)时,系统会陷入死循环。通过日志分析,错误表现为file_text error
,导致Agent无法正常完成响应生成。

日志片段:
LLMSummarizingCondenserConfig(type='llm', llm_config=LLMConfig(model='openrouter/anthropic/claude-3.7-sonnet',
api_key='******', base_url='', api_version=None, ... max_output_tokens=8192, ... reasoning_effort='high', seed=None),
keep_first=4, max_size=80, max_event_length=10000)
问题链接: GitHub - OpenHands Issue #8413
技术分析与解决方案
深入源码后,定位到问题出在llm.py
文件的第406-421行。OpenHands对max_output_tokens
参数有特殊处理逻辑,但这个逻辑只考虑了官方API提供的claude-3-7-sonnet
模型,而没有考虑OpenRouter提供的claude-3.7-sonnet
模型(注意命名差异)。
问题代码段:
if 'claude-3-7-sonnet' in self.config.model:
self.config.max_output_tokens = 64000 # litellm set max to 128k, but that requires a header to be set
修复过程:
- 分析了参数传递路径,确认问题在模型名称匹配逻辑
- 发现通过OpenRouter使用的模型命名与官方API不同(使用
.
而非-
) - 扩展了条件判断,同时处理两种命名格式
- 编写测试用例验证修复在不同提供商情况下都能正确工作
PR中的修复代码:
if any(
model in self.config.model
for model in ['claude-3-7-sonnet', 'claude-3.7-sonnet']
):
self.config.max_output_tokens = 64000 # litellm set max to 128k, but that requires a header to be set
PR链接: GitHub - OpenHands Pull Request #8415
结语
看到PR被Approved, Merged还是让人难掩兴奋的哈哈,尤其OpenHands社区响应迅速,并提供了有建设性的反馈,无怪乎OpenHands能更新迭代如此迅速。也特别欣赏项目维护者对代码质量的高要求和对细节的关注 - 即使是看似简单的一行修改,也经过了严格的审查流程(顺便学习了下Lint代码语法检测的使用哈哈)。
Remarkable Day, Help Yourself is Help Others, 未来可期!