Microsoft Agent Framework 的一行修復方案,經程式碼審查揭出兩處問題
My fix was one line. Code review found two holes in it.
修正 Microsoft Agent Framework 的 Gemini 串流模型名稱遺失問題時,程式碼審查找出一行修復方案中的兩處錯誤。回退模型應採用該次請求解析出的模型,而非客戶端預設模型;串流處理亦須保留伺服器回報的版本,避免後續未帶版本的區塊將其覆蓋。最終修正經三輪修改並加入四項測試,涵蓋版本保留及不同模型回退情況。
The bug I fixed in Microsoft Agent Framework did not crash anything. That is what made it worth fixing.
When the framework called Gemini without streaming, the response knew which model had answered. When it made the same call with streaming, the model name could disappear on the way. The framework records its metrics through OpenTelemetry, and the model name is one of the dimensions those metrics are split by. On streamed calls, the token and duration histograms simply lost that dimension. Every request still succeeded. The per-model view of cost and latency just had a hole in it.
Why it happened
Each streamed chunk from Gemini may or may not carry a model_version. The streaming parser copied that field straight into the update, so a chunk without it produced an update without a model. The aggregator keeps the last non-empty value it sees, and there was nothing to catch up afterwards, so a stream whose chunks carried no version ended with no model at all.
The non-streaming parser, thirty-odd lines above, already handled this: it fell back to the configured model when the response did not name one. Two paths, same input type, different answers.
The one-line fix
So I proposed the obvious thing: apply the same fallback on the streaming path. One line, two tests, parity with the sibling.
It was wrong twice.
Hole one
I had raised this one myself, as an open question in the PR description: was the client's default model really the right fallback? The automated reviewer answered it. The fallback used the client's default model, not the model actually requested. A client configured for gemini-2.5-flash and called with gemini-2.5-pro for one request would label that request as Flash, metrics included. The model resolved for the request was already in scope where the stream was consumed, so the parser now takes it as an argument and falls back to that.
Hole two
Then the maintainer found the subtler one. Applying the fallback chunk by chunk could overwrite a version the server had already reported. If an early chunk said gemini-2.5-pro-002 and the final usage chunk carried no version, the aggregator, which keeps the last non-empty value, would replace the precise version with the requested alias gemini-2.5-pro.
The fix had to remember what the server said for the whole stream, not chunk by chunk:
fallback_model = model
async for chunk in response_stream:
if chunk.model_version:
fallback_model = chunk.model_version
yield self._process_chunk(chunk, fallback_model)
and in the parser:
model=chunk.model_version or model,
What merged
Three iterations, four tests. One checks the version from a chunk is kept, one checks the fallback to the configured model, one the fallback to the requested model, and one replays the maintainer's exact case: an observed server version must survive a later chunk that omits it. The last one fails on the previous commit, which is the point of it.
What I take from it
My first version was not careless. It matched the sibling path exactly, it had tests, and it fixed the reported symptom. It was still wrong, twice. The first hole I had seen and left as a question. The second came from the maintainer.
That is the case for review in one PR. Not catching typos, but catching the second-order behaviour of a change: which value is in scope, what the aggregator does with it next, what a later chunk can undo. Observability bugs make this harder, because nothing fails. The only signal is a number that is quietly attached to the wrong thing, or to nothing.
If you run LLM calls behind OpenTelemetry, it is worth one test that compares a streamed call with a non-streamed one and checks every attribute, not just the status code.
The PR, with the full review thread: microsoft/agent-framework#9139
I am Ayoub Hammoudi, a backend and AI platforms engineer in Paris. More of my work is at github.com/Ayoubhm07.
來源:DEV Community · dev.to