Chat Simulation & Fix My Agent
Run a chat agent through agent-simulate against your platform scenarios, then diagnose failures with Fix My Agent.
Wire a LiteLLM-backed chat agent into agent-simulate, run it against your platform scenarios with TestRunner, and use Fix My Agent to turn the results into prioritized fixes.
| Time | Difficulty | Package |
|---|---|---|
| 20 min | Intermediate | agent-simulate |
- Future AGI account with an agent definition and chat-type scenarios already created (see Simulation overview)
- A run test built against a chat agent definition, with chat scenarios ticked and evals attached (see Create a simulation)
- API keys:
FI_API_KEYandFI_SECRET_KEY(see Get your API keys) - An LLM provider key for the agent’s model (OpenAI, Gemini, or Anthropic)
- Python 3.11
Install
pip install agent-simulate litellm futureagi
export FI_API_KEY="your-api-key"
export FI_SECRET_KEY="your-secret-key"
export GEMINI_API_KEY="your-llm-provider-key"
Tutorial
Load your keys and import the SDK
import os
import asyncio
import litellm
from fi.simulate import TestRunner, AgentInput
from fi.prompt import Prompt
FI_API_KEY = os.environ["FI_API_KEY"]
FI_SECRET_KEY = os.environ["FI_SECRET_KEY"]
print("Loaded FI_API_KEY and FI_SECRET_KEY" if FI_API_KEY and FI_SECRET_KEY else "Missing a key")You should see Loaded FI_API_KEY and FI_SECRET_KEY. fi.simulate is the agent-simulate package’s import namespace; fi.prompt ships from futureagi.
Fetch the prompt template your agent runs on
PROMPT_NAME = "Customer_support_agent"
PROMPT_LABEL = "production"
prompt = Prompt.get_template_by_name(PROMPT_NAME, label=PROMPT_LABEL)
compiled = prompt.compile()
system_prompt = next(
(m.get("content") for m in compiled if m.get("role") == "system"), ""
)
model_name = prompt.template.model_configuration.model_name
print(f"Loaded '{PROMPT_NAME}' ({PROMPT_LABEL}) on {model_name}")You should see something like Loaded 'Customer_support_agent' (production) on gpt-4o-mini. compile() returns the same message list you’d hand to any LLM provider, so pulling the system message out of it keeps the simulation in sync with whatever you edit in the Prompt Workbench. Called with no kwargs, compile() leaves any {{variable}} placeholders unsubstituted, so those markers land in system_prompt verbatim. Use .get() rather than indexing: unresolved placeholder entries in compiled carry no role key, and chat prompts routinely have at least one.
Build the agent function
def build_agent(system_prompt: str, model: str):
async def agent_function(input_data: AgentInput) -> str:
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.extend(input_data.messages)
if input_data.new_message:
messages.append(input_data.new_message)
response = await litellm.acompletion(
model=model,
messages=messages,
temperature=0.2,
)
return response.choices[0].message.content or ""
return agent_function
agent_callback = build_agent(system_prompt, model_name)
test_input = AgentInput(messages=[], new_message={"role": "user", "content": "What's your refund policy?"})
test_reply = asyncio.run(agent_callback(test_input))
print(test_reply)You should see a plausible reply about a refund policy printed to the console. agent_function is what TestRunner calls once per turn. AgentInput.messages carries the conversation so far and new_message carries the scenario’s next line; litellm routes model to whichever provider it belongs to. Confirming the reply here proves the LiteLLM model string works before you spend a full run finding out it doesn’t.
Run the simulation
Warning
A high concurrency value against a rate-limited LLM provider produces throttling errors mid-run. Start at 5 and raise it once you confirm your provider’s rate limit clears it.
RUN_TEST_NAME = "Chat regression test"
CONCURRENCY = 5
async def main():
runner = TestRunner(api_key=FI_API_KEY, secret_key=FI_SECRET_KEY)
return await runner.run_test(
run_test_name=RUN_TEST_NAME,
agent_callback=agent_callback,
concurrency=CONCURRENCY,
)
report = asyncio.run(main())You should see the SDK’s own console output as the run progresses: 🔍 Fetching Run Test ID for name: ..., then ✓ Test Execution Started: ..., and finally ✅ Cloud Simulation Completed.. run_test_name must match a run test you’ve already configured on the platform, and concurrency caps how many conversations run in parallel. The cloud path always returns report.results empty: results are read on the platform in the next step, not off the returned object.
Open the run and check the metrics
Go to app.futureagi.com → Simulation → your run test name. You should see one row per conversation with the evaluation scores your run test configured (task completion, tone, groundedness, or whatever you attached).
On the refund-policy scenario, say task completion scores low (illustrative, not a score we actually observed here, but the kind of row that sends you to Fix My Agent).
Diagnose failures with Fix My Agent
Fix My Agent stays greyed out until the run has at least 15 connected calls, so a scenario set small enough to finish fast won’t unlock it.
From the run’s results page, click Fix My Agent. The panel opens empty the first time: it shows “There are no suggestions yet, click the refresh button to get suggestions”, so click refresh. Once populated, it reads every conversation against your evaluation criteria. It returns a ranked list of issues, each with a heading, a priority (High/Medium/Low), a written recommendation, and a Calls Affected count.
For the refund-policy failure, an entry might read: “Agent gives inconsistent refund windows” (High priority, 6 calls affected), recommending the system prompt state the refund window as a fixed number of days instead of leaving it to the model’s judgment. There’s no prompt text to copy here. Instead, click Optimize My Agent, which opens optimization setup scoped to this run and its findings.
Tip
Implement the high-priority suggestions first, commit a new prompt version, then re-run this same run test. Compare task completion on the refund-policy scenario before and after to confirm the fix landed before promoting it to production.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Prompt.get_template_by_name raises a not-found error | Template name or label doesn’t match what’s in the dashboard | Names are case-sensitive; open Prompts in the dashboard and copy the exact name and label |
run_test raises immediately with an auth error | FI_API_KEY or FI_SECRET_KEY is missing, expired, or wrong project | Regenerate keys in admin settings and re-export them |
| Run finishes but the Simulated runs tab shows zero conversations | The run test’s scenarios are voice-type instead of chat-type | Rebuild the run test against a chat agent definition so the wizard narrows to chat scenarios |
| Simulation stalls or times out under load | concurrency outpaces your LLM provider’s rate limit | Lower concurrency to 1-3 and confirm single-conversation runs succeed first |
agent_function returns empty strings | response.choices[0].message.content came back None because the provider returned an empty completion, or the model name isn’t callable with your key | Confirm model_name matches a model your provider key can call |
| Fix My Agent is greyed out | The run is still in progress, or it has fewer than 15 connected calls | Wait for the run to complete, and hover the button to see which condition the tooltip names; add scenarios if the run is too small |
Continue with the Fix My Agent guide to see every diagnostic field it returns and how to hand its findings to Optimize My Agent.
Questions & Discussion