模型到底在想什么?eino 的 reasoning_content 全链路走读
【免费下载链接】einoThe ultimate LLM/AI application development framework in Go.项目地址: https://gitcode.com/GitHub_Trending/ei/eino
凌晨排查一个 Agent 答非所问的问题:日志里只有最终答案,模型为什么这么答,完全靠猜。打开 eino 的消息结构,你会看到reasoning_content字段——它把模型的思考原文存在ChatMessage里,随每次调用返回。拿到它,调试就不用蒙。
为什么只有答案不够用
只拿到content,你只能看到结论,看不到推导。模型选错工具时,你不知它依据哪句话做的判断;用户说答非所问时,你无法复现当时的推理路径;提示词调优只能反复试错。
更要命的是,中间件裁剪消息时若丢掉思考过程,后续多轮调用会丢失关键上下文。看不到推导链条,调试、归因、优化都没抓手。
字段怎么流转:从数据层到编排层
这个字段自下而上分三层走。
数据层:schema/message.go 在ChatMessage上定义——
// 模型返回的思考原文,为空则不参与序列化 ReasoningContent string `json:"reasoning_content,omitempty"`白话说:它存的是模型推理的原始文本;omitempty让没有思考时 JSON 里不出现这个键。
组件层:模型适配器负责填充。以 schema/openai/extension.go 为例,它把 OpenAI 兼容接口返回的 reasoning 片段解析进该字段;流式场景下ConcatMessages再把分片逐段拼接成完整思考链。
编排层:compose图执行时,字段随消息在节点间流动;adk 中间件也会尊重它——reduction 裁剪旧工具结果时保留思考内容,summarization 统计消息长度时把它计入。
三个能落地的场景
工具调用出错时归因
场景:adk agent 选错工具,答案跟着跑偏。做法:读那一轮ChatMessage上挂的reasoning_content,看模型选工具时盯着用户的哪句话,再对照工具描述。收益:你能直接判断是描述写得歧义还是提示词的问题,不用整链重跑。
长对话压缩前留底
场景:多轮对话很长,上下文压缩后旧推理会消失。做法:在 summarization 和 reduction 生效前,把关键轮次的思考字段写进本地日志。收益:日后回查历史问题,还能找到模型当时的决策依据,而不是只剩一句干巴巴的结论。
提示词 A/B 对比
场景:系统提示词改了一行,说不清是变好还是变坏。做法:同一组问题跑两个版本,各收集reasoning_content,逐条对比推理路径的分叉点。收益:你能看到新提示词在模型行为上改变了什么,A/B 结论不再凭感觉。
三步拿到思考原文
- 挂载会输出思考的模型,如 DeepSeek-R1、OpenAI o 系列。
- 照常调用
Generate或Stream,从返回的resp[0].ReasoningContent读取。 - 字段为空时,先确认模型这一轮是否真的走了思考模式 🔍
调试时看哪三处
- 看
ReasoningTokens,确认思考花了多少 token - 查流式分片拼接是否完整
- 压缩前把思考字段导出到日志 📌
你实际得到什么
- 调试有了证据:答错时能查到是推理哪一步走偏的。
- 用户能看到"怎么得出的",信任更好建立。
- 提示词与工具描述的调整有了对照物,优化不再是黑盒。
接下来会怎样
越来越多模型默认输出思考内容,reasoning_content这类字段会成为消息结构里的标准成员。eino 已为它留好位置,你搭下一个 Agent 时直接读走就行。✨
【免费下载链接】einoThe ultimate LLM/AI application development framework in Go.项目地址: https://gitcode.com/GitHub_Trending/ei/eino
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考