feat(examples): add chatbot scan example#2472
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new example for scanning stateful chatbots using the Giskard LLM response API, including a sample script, environment configuration, and the addition of the python-dotenv dependency. The review feedback focuses on improving the robustness and readability of the example code, specifically by ensuring cleaner string interpolation for message objects and adding safety checks to handle empty LLM responses.
| return "\n".join( | ||
| f"[user]: {i.inputs}\n[assistant]: {i.outputs}" for i in self.interactions | ||
| ) |
There was a problem hiding this comment.
In _repr_prompt_, interpolating the UserMessage and AssistantMessage objects directly into the string will likely result in a verbose representation (e.g., content='...' role='user') because they are Pydantic models. It is better to access the .content attribute for a cleaner prompt representation.
| return "\n".join( | |
| f"[user]: {i.inputs}\n[assistant]: {i.outputs}" for i in self.interactions | |
| ) | |
| return "\n".join( | |
| f"[user]: {i.inputs.content}\n[assistant]: {i.outputs.content}" for i in self.interactions | |
| ) |
|
|
||
| result = await acompletion(MODEL, [_SYSTEM_MESSAGE] + trace.messages + [inputs]) | ||
|
|
||
| return result.choices[0].message |
There was a problem hiding this comment.
Accessing result.choices[0] without checking if choices is non-empty can lead to an IndexError if the LLM returns an empty response. Adding a check improves the robustness of the example, especially when dealing with potential refusals or API-specific edge cases.
| return result.choices[0].message | |
| if not result.choices: | |
| raise RuntimeError("The LLM returned an empty response (no choices).") | |
| return result.choices[0].message |
There was a problem hiding this comment.
Code Review
This pull request introduces a new example script, chatbot_scan.py, which demonstrates how to scan a stateful chatbot using the Giskard LLM response API. The changes include a custom LLMTrace implementation, a sample environment configuration file, and the addition of the python-dotenv dependency. Feedback for this PR suggests improving the readability of trace representations by accessing message content directly and implementing a safety check for LLM response choices to prevent potential index errors.
| if not self.interactions: | ||
| return "**No interactions yet**" | ||
| return "\n".join( | ||
| f"[user]: {i.inputs}\n[assistant]: {i.outputs}" for i in self.interactions |
There was a problem hiding this comment.
The string interpolation of i.inputs and i.outputs will likely produce a verbose Pydantic model representation (e.g., UserMessage(role='user', content='...')) instead of just the text content. Accessing the .content attribute directly ensures a cleaner and more readable trace in the generated report.
| f"[user]: {i.inputs}\n[assistant]: {i.outputs}" for i in self.interactions | |
| f"[user]: {i.inputs.content}\n[assistant]: {i.outputs.content}" for i in self.interactions |
|
|
||
| result = await acompletion(MODEL, [_SYSTEM_MESSAGE] + trace.messages + [inputs]) | ||
|
|
||
| return result.choices[0].message |
There was a problem hiding this comment.
Accessing result.choices[0] directly can lead to an IndexError if the LLM provider returns an empty list of choices (e.g., due to content filtering or other API-side issues). It is safer to verify that choices is not empty before accessing it.
if not result.choices:\n raise RuntimeError("LLM returned no choices. Check for content filtering or API errors.")\n return result.choices[0].messageCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3da4761 to
0587445
Compare
Summary
examples/chatbot_scan/— an end-to-end example showing how to scan a stateful LLM chatbot with a generated suiteacompletion; conversation history is threaded through a typedLLMTracesubclass.env.exampleprovided;python-dotenvloads credentials so no key is ever inlined in the run commandgenerate_suite, run against the chatbot target, and the fullSuiteResultis serialised toresult.jsonTest plan
.env.example→.env, setOPENAI_API_KEYuv run python examples/chatbot_scan/chatbot_scan.pycompletes without errorresult.jsonis written toexamples/chatbot_scan/🤖 Generated with Claude Code