Repository navigation
Replaying a Semantic Kernel run with no provider reachable — and why OPENAI_BASE_URL is the only lever #14447
Xizhuo (xizhuomengcontin)
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
I record agent and pipeline runs at the HTTP boundary to the model provider — from outside the process — and serve the recording back so the run happens again with no provider called. I checked it against Semantic Kernel tonight. It works with zero configuration, and while finding out why, I ran into a Python-connector detail that seems worth writing down on its own.
The detail
OpenAIChatCompletion.__init__takes:There is no
base_urlparameter. And inopen_ai_config_base.pythe client is built as:base_urlis never passed, so the OpenAI SDK's own fallback governs — it readsOPENAI_BASE_URLfrom the environment. (The Azure path is different:AzureOpenAISettingsdoes exposebase_url/AZURE_OPENAI_BASE_URL.)The practical consequence for anyone pointing SK at an OpenAI-compatible gateway, vLLM, or a local server: for the non-Azure
OpenAIChatCompletionthere are exactly two routes — setOPENAI_BASE_URL, or construct your ownAsyncOpenAIand pass it asasync_client. There is no constructor argument for it, which is not obvious from the signature until you go looking. If that is intentional, it might be worth a line in the docstring; if the asymmetry with the Azure connector is accidental, that is a small fix.What that makes possible
Because the origin comes from the environment, a recorder that launches your script as a child process with that one variable redirected captures SK with no code change at all:
Then, with the origin process killed so there is nothing upstream to reach:
exact=1means the replayed request matched the recording byte for byte — chat history assembly, execution settings, headers and all. The kernel, the service resolution and your own code run for real; only the model's answer comes from the trace. Nothing is installed into SK: no filter, no telemetry hook, no patched client.Two things that buys you: a misbehaving run becomes a file a colleague can re-run without your key and without spending tokens, and the same file pins a kernel configuration in CI — which is the awkward part of testing anything with a chat completion in it, since real calls cost money and do not answer the same way twice.
Tested with
semantic-kernel1.44.1 on Python 3.12 against a deterministic local origin standing in for a provider, so "byte for byte" is a real comparison rather than a model happening to repeat itself.Limits, stated rather than buried
/v1/embeddingsis not one of the claimed paths), so a memory/RAG-heavy kernel that embeds at query time cannot be fully replayed today. Replay refuses those calls with an explicit error rather than serving a wrong vector. I mention it because SK's memory connectors make this a realistic case, and I would rather state it than have someone find out at replay time..NET, or Java. The reasoning above is specific to the PythonOpenAIChatCompletion.Tool is OrcaReplay (Apache-2.0, npm, Node 20+); I maintain it, so weigh the post accordingly. The connector observation at the top stands on its own — it is about SK's signature and client construction, not about my tool.
All reactions