Skip to content

Commit 4974b21

Browse files
committed
feat(examples): add session replay, tool security scan, eval pipeline (#89, #90, #91)
- Session/Memory multi-backend replay consistency testing framework - Tool execution security scanning with filter/monitoring - Evaluation + Optimization auto-regression pipeline - All built on trpc-agent-sdk with Hy3 LLM backend Fixes #89, Fixes #90, Fixes #91 Assisted-by: claude-code:deepseek-v4-pro
1 parent 913eff7 commit 4974b21

18 files changed

Lines changed: 571 additions & 0 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Evaluation + Optimization Pipeline
2+
3+
Auto-regression testing and prompt optimization closed loop built with
4+
tRPC-Agent SDK + Hy3 LLM.
5+
6+
## Features
7+
8+
- **Eval cases**: Built-in test cases with keyword-based scoring
9+
- **Auto-regression**: Compare scores across prompt iterations
10+
- **Optimization**: Iterative prompt improvement based on eval feedback
11+
- **Extensible**: Add custom eval cases and scoring functions
12+
13+
## Quick Start
14+
15+
```bash
16+
export TRPC_AGENT_API_KEY=your-key
17+
export TRPC_AGENT_BASE_URL=https://tokenhub.tencentmaas.com/v1
18+
python run_agent.py
19+
```
20+
21+
## Pipeline
22+
23+
```
24+
Eval Cases → score_response → optimize_prompt → new prompt → re-eval → regress
25+
```

examples/eval_optimization/agent/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from trpc_agent_sdk.agents import LlmAgent
2+
from trpc_agent_sdk.models import LLMModel, OpenAIModel
3+
from trpc_agent_sdk.tools import FunctionTool
4+
from .config import get_model_config
5+
from .tools import list_eval_cases, score_response, optimize_prompt
6+
7+
INSTRUCTION = """You are an evaluation and prompt optimization assistant.
8+
Run eval test cases with score_response, analyze regressions, and use
9+
optimize_prompt to iteratively improve prompts based on scores.
10+
11+
When a prompt fails tests, analyze why and suggest concrete improvements.
12+
Track baseline scores and compare after each optimization iteration."""
13+
14+
15+
def _create_model() -> LLMModel:
16+
api_key, url, model_name = get_model_config()
17+
return OpenAIModel(model_name=model_name, api_key=api_key, base_url=url)
18+
19+
20+
def create_agent() -> LlmAgent:
21+
return LlmAgent(
22+
name="eval_optimizer",
23+
description="Evaluation + Optimization auto-regression pipeline.",
24+
model=_create_model(),
25+
instruction=INSTRUCTION,
26+
tools=[
27+
FunctionTool(list_eval_cases),
28+
FunctionTool(score_response),
29+
FunctionTool(optimize_prompt),
30+
],
31+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import os
2+
3+
def get_model_config():
4+
api_key = os.environ.get("TRPC_AGENT_API_KEY", "EMPTY")
5+
url = os.environ.get("TRPC_AGENT_BASE_URL", "http://127.0.0.1:8000/v1")
6+
model_name = os.environ.get("TRPC_AGENT_MODEL_NAME", "hy3")
7+
return api_key, url, model_name
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""Evaluation and prompt optimization pipeline tools.
2+
3+
Provides:
4+
- eval_cases registry with expected outputs
5+
- run_eval to execute test cases and score results
6+
- optimize_prompt to iteratively improve prompts based on eval regression
7+
"""
8+
9+
import json
10+
import time
11+
from dataclasses import dataclass, field
12+
from datetime import datetime
13+
14+
15+
@dataclass
16+
class EvalCase:
17+
id: str
18+
input: str
19+
expected_keywords: list[str] = field(default_factory=list)
20+
max_tokens: int = 500
21+
temperature: float = 0.3
22+
23+
24+
@dataclass
25+
class EvalResult:
26+
case_id: str
27+
passed: bool
28+
response: str
29+
score: float # 0.0 - 1.0
30+
missing_keywords: list[str] = field(default_factory=list)
31+
duration_ms: float = 0.0
32+
33+
34+
@dataclass
35+
class PromptVariant:
36+
version: int
37+
prompt: str
38+
avg_score: float = 0.0
39+
eval_count: int = 0
40+
created_at: str = field(default_factory=lambda: datetime.now().isoformat())
41+
42+
43+
# Built-in eval cases — extend by adding more
44+
BUILTIN_CASES = [
45+
EvalCase(id="greet", input="Say hello in one sentence.",
46+
expected_keywords=["hello", "hi"], max_tokens=50),
47+
EvalCase(id="math", input="What is 2+2? Answer with just the number.",
48+
expected_keywords=["4"], max_tokens=20),
49+
EvalCase(id="code", input="Write a Python function that returns the sum of two numbers.",
50+
expected_keywords=["def", "return", "+"], max_tokens=200),
51+
]
52+
53+
54+
def list_eval_cases() -> list[dict]:
55+
"""List all registered evaluation test cases."""
56+
return [{"id": c.id, "input": c.input, "keywords": c.expected_keywords}
57+
for c in BUILTIN_CASES]
58+
59+
60+
def score_response(response: str, expected_keywords: list[str]) -> dict:
61+
"""Score a response against expected keywords. Returns {score, missing}."""
62+
lower = response.lower()
63+
missing = [k for k in expected_keywords if k.lower() not in lower]
64+
hit = len(expected_keywords) - len(missing)
65+
score = hit / len(expected_keywords) if expected_keywords else 1.0
66+
return {"score": round(score, 2), "missing": missing, "hits": hit}
67+
68+
69+
def optimize_prompt(current_prompt: str, eval_scores: list[float],
70+
failure_analysis: str = "") -> dict:
71+
"""Analyze eval scores and suggest prompt optimization.
72+
73+
Returns: {"version": int, "suggested_prompt": str, "analysis": str}
74+
"""
75+
avg = sum(eval_scores) / len(eval_scores) if eval_scores else 0.0
76+
77+
suggestions = []
78+
if avg < 0.5:
79+
suggestions.append("Add explicit formatting instructions.")
80+
if "missing" in failure_analysis.lower():
81+
suggestions.append("Include required output keywords in the prompt.")
82+
if not suggestions:
83+
suggestions.append("Prompt performing well. Minor tuning may help.")
84+
85+
version = int(time.time())
86+
optimized = current_prompt.strip()
87+
if suggestions:
88+
optimized += "\n\nAdditional instructions:\n- " + "\n- ".join(suggestions)
89+
90+
return {
91+
"version": version,
92+
"avg_score": round(avg, 2),
93+
"suggestions": suggestions,
94+
"suggested_prompt": optimized,
95+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Evaluation + Optimization auto-regression pipeline.
2+
3+
Usage::
4+
5+
export TRPC_AGENT_API_KEY=your-key
6+
export TRPC_AGENT_BASE_URL=https://tokenhub.tencentmaas.com/v1
7+
python run_agent.py
8+
"""
9+
10+
import asyncio
11+
from trpc_agent_sdk.runners import Runner
12+
from trpc_agent_sdk.sessions import InMemorySessionService
13+
from agent.agent import create_agent
14+
15+
16+
async def main():
17+
agent = create_agent()
18+
session_service = InMemorySessionService()
19+
20+
prompt = (
21+
"List eval cases, then score this response against the 'greet' case "
22+
"(expected keywords: hello, hi): 'Hey there!'. "
23+
"Finally run optimize_prompt with the current prompt: "
24+
"'You are a helpful assistant' and eval scores [0.6, 0.8, 0.5]."
25+
)
26+
27+
runner = Runner(agent=agent, session_service=session_service)
28+
async for event in runner.run(prompt):
29+
if event.content:
30+
print(event.content, end="", flush=True)
31+
print()
32+
33+
34+
if __name__ == "__main__":
35+
asyncio.run(main())
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Session / Memory Replay Consistency Testing
2+
3+
Multi-backend replay and consistency verification framework built with
4+
tRPC-Agent SDK. Tests that conversations produce consistent results
5+
across different session and memory backends.
6+
7+
## Supported Backends
8+
9+
- **Session**: InMemory, Redis, SQL
10+
- **Memory**: InMemory, Mem0, MemPalace, Redis, SQL
11+
12+
## Quick Start
13+
14+
```bash
15+
pip install -e '.[redis,sql,mem0]'
16+
export TRPC_AGENT_API_KEY=your-key
17+
export TRPC_AGENT_BASE_URL=https://tokenhub.tencentmaas.com/v1
18+
python run_agent.py
19+
```
20+
21+
## Architecture
22+
23+
```
24+
User → Agent (Hy3 LLM)
25+
├── list_available_backends()
26+
├── replay_conversation(session, memory, messages)
27+
└── compare_replays(results) → consistency report
28+
```

examples/session_replay_test/agent/__init__.py

Whitespace-only changes.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from trpc_agent_sdk.agents import LlmAgent
2+
from trpc_agent_sdk.models import LLMModel, OpenAIModel
3+
from trpc_agent_sdk.tools import FunctionTool
4+
from .config import get_model_config
5+
from .tools import list_available_backends, replay_conversation, compare_replays
6+
7+
INSTRUCTION = """You are a session/memory consistency testing assistant.
8+
Help users replay conversations across different session and memory backends,
9+
then compare the results for consistency.
10+
11+
Use list_available_backends to discover available backends.
12+
Use replay_conversation to run replays.
13+
Use compare_replays to check consistency across backends."""
14+
15+
16+
def _create_model() -> LLMModel:
17+
api_key, url, model_name = get_model_config()
18+
return OpenAIModel(model_name=model_name, api_key=api_key, base_url=url)
19+
20+
21+
def create_agent() -> LlmAgent:
22+
return LlmAgent(
23+
name="session_replay_tester",
24+
description="Session/Memory multi-backend replay consistency tester.",
25+
model=_create_model(),
26+
instruction=INSTRUCTION,
27+
tools=[
28+
FunctionTool(list_available_backends),
29+
FunctionTool(replay_conversation),
30+
FunctionTool(compare_replays),
31+
],
32+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import os
2+
3+
def get_model_config():
4+
api_key = os.environ.get("TRPC_AGENT_API_KEY", "EMPTY")
5+
url = os.environ.get("TRPC_AGENT_BASE_URL", "http://127.0.0.1:8000/v1")
6+
model_name = os.environ.get("TRPC_AGENT_MODEL_NAME", "hy3")
7+
return api_key, url, model_name

0 commit comments

Comments
 (0)