-
Notifications
You must be signed in to change notification settings - Fork 0
🐛 JSONL 格式解析错误:JSON 选项内容意外显示在聊天主文本中 #23
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
问题描述
在聊天界面中,AI 返回的响应内容出现了格式化错误。原本应该被解析为选项的 JSONL 格式内容意外显示在了主聊天文本中,导致用户看到原始的 JSON 字符串而不是格式化的内容。
重现步骤
- 在聊天界面中发送一个需要 AI 返回推荐选项的消息
- AI 回复包含 JSONL 格式的推荐选项
- 观察到原始 JSON 内容显示在聊天文本中,而不是被解析为选项按钮
期望行为
- JSONL 格式的推荐选项应该被正确解析
- 主聊天文本中不应显示原始 JSON 字符串
- 解析后的选项应该显示在右侧选项面板中
实际行为
- 原始 JSON 字符串显示在主聊天文本中
- 选项解析失败或不完整
- 用户界面混乱,影响阅读体验
技术分析
根据代码分析,问题出现在 NextStepChat.tsx 的 splitContentAndOptions 函数中:
问题根因
- 反向扫描逻辑缺陷:函数从文本末尾向前扫描 JSON 行,但在遇到第一个空行或非 JSON 行时就停止了
- 混合内容处理不当:当 JSONL 选项与主文本内容混合在一起时,解析逻辑无法正确分离
- 空行判断过于严格:函数在遇到空行时立即停止扫描,导致前面的有效 JSON 行被遗漏
具体问题位置
文件:src/components/NextStepChat.tsx
函数:splitContentAndOptions (第63-96行)
关键逻辑:第72行 if (!line) break; 导致扫描过早停止
解决方案
1. 改进 JSONL 解析逻辑
function splitContentAndOptions(raw: string): { main: string; options: NextStepOption[] } {
if (!raw) return { main: '', options: [] };
const lines = raw.split('\n');
const collected: NextStepOption[] = [];
const jsonLineIndices: number[] = [];
// 扫描所有行,识别有效的 JSONL 行
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;
try {
const obj = JSON.parse(line);
if (
obj && typeof obj === 'object' &&
(obj.type === 'deepen' || obj.type === 'next') &&
typeof obj.content === 'string' &&
typeof obj.describe === 'string'
) {
collected.push({
type: obj.type,
content: obj.content,
describe: obj.describe
});
jsonLineIndices.push(i);
}
} catch {
// 不是 JSON,继续扫描
}
}
// 移除识别出的 JSON 行,保留主内容
const mainLines = lines.filter((_, index) => !jsonLineIndices.includes(index));
const main = mainLines.join('\n').trim();
return { main, options: collected.slice(0, 6) };
}2. 增强错误处理
// 添加调试日志
console.log('Raw response:', raw);
const result = splitContentAndOptions(raw);
console.log('Parsed main:', result.main);
console.log('Parsed options:', result.options);3. 改进流式响应处理
在 sendMessageInternal 函数中,确保流式响应完成后正确解析:
() => {
// finalize parse options with improved error handling
try {
const { main, options: incoming } = splitContentAndOptions(assembled);
// 更新消息内容,移除 JSON 部分
setMessages((prev: ChatMessage[]) =>
prev.map((m: ChatMessage) =>
m.id === assistantId ? { ...m, content: main || assembled } : m
)
);
if (incoming.length) {
mergeOptions(incoming, assistantId);
}
} catch (error) {
console.error('Failed to parse options:', error);
// 降级处理:至少显示完整响应
}
setIsLoading(false);
}优先级
🔴 高优先级 - 影响核心用户体验,需要立即修复
附加信息
- 浏览器:所有主流浏览器
- 组件:NextStepChat
- 影响范围:所有聊天会话中的选项解析
- 修复难度:中等(需要重构解析逻辑)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working