Multi-Turn Workflow
Orchestrate three sequential Pydantic AI agents — a classifier, a risk assessor, and a decision agent — under a single VeriProof session. Each agent run is a separate step with its own governance metadata, but all steps share a single Merkle-sealed audit trail.
Prerequisites
pip install veriproof-sdk veriproof-sdk-instrumentation-pydantic-ai pydantic-aiEnvironment
VERIPROOF_API_KEY=vp_cust_your-tenant.<key-material>
VERIPROOF_APPLICATION_ID=loan-workflow
ANTHROPIC_API_KEY=sk-ant-...Complete example
import asyncio
import os
from veriproof_sdk import (
configure_veriproof,
VeriproofClientOptions,
AgentRole,
DecisionType,
RiskLevel,
SessionIntent,
)
from veriproof_sdk_instrumentation_pydantic_ai import VeriproofPydanticAISession
from pydantic_ai import Agent
from pydantic_ai.models.anthropic import AnthropicModel
configure_veriproof(
VeriproofClientOptions(
api_key=os.environ["VERIPROOF_API_KEY"],
application_id=os.environ["VERIPROOF_APPLICATION_ID"],
),
service_name=os.environ["VERIPROOF_APPLICATION_ID"],
set_global=True,
)
# ── Agent definitions ──────────────────────────────────────────────────────
classify_agent = Agent(
AnthropicModel("claude-3-5-haiku-20241022"),
system_prompt=(
"Classify the loan application. "
"Return one of: STANDARD | COMPLEX | HIGH_RISK. "
"Respond with the classification only."
),
)
risk_agent = Agent(
AnthropicModel("claude-3-5-haiku-20241022"),
system_prompt=(
"You are a credit risk analyst. "
"Given a loan classification and financials, produce a risk score (0–100) "
"and list up to 3 risk factors. Format: SCORE:<n> FACTORS:<factor1>|<factor2>"
),
)
decision_agent = Agent(
AnthropicModel("claude-3-5-sonnet-20241022"),
system_prompt=(
"You are a senior loan officer. "
"Based on the classification and risk assessment, make a final APPROVE or DECLINE decision. "
"State the reason in one sentence."
),
)
async def process_loan_application(applicant_id: str, credit_score: int, income: float) -> dict:
"""Run the full three-step loan decision workflow under a single VeriProof session."""
application_summary = (
f"Applicant: {applicant_id}. "
f"Credit score: {credit_score}. "
f"Annual income: ${income:,.0f}. "
f"Requested loan: $25,000. Debt-to-income ratio: 0.34."
)
# Create one session shared across all three agent runs.
# All agent_run spans carry the same veriproof.session.id.
session = VeriproofPydanticAISession(
session_intent=SessionIntent.ADVISORY,
decision_type=DecisionType.APPROVAL,
agent_role=AgentRole.SPECIALIST,
)
# ── Step 1: Classify ──────────────────────────────────────────────
classify_result = await session.run(classify_agent, application_summary)
classification = classify_result.data.strip()
# ── Step 2: Risk assessment ───────────────────────────────────────
risk_prompt = f"{application_summary} Classification: {classification}."
risk_result = await session.run(risk_agent, risk_prompt)
risk_text = risk_result.data
# Parse score from response (e.g. "SCORE:42 FACTORS:high-dti|limited-history")
risk_score = 50 # default
if "SCORE:" in risk_text:
try:
risk_score = int(risk_text.split("SCORE:")[1].split()[0])
except (ValueError, IndexError):
pass
risk_level = (
RiskLevel.HIGH if risk_score >= 70
else RiskLevel.MEDIUM if risk_score >= 40
else RiskLevel.LOW
)
session.set_risk_level(risk_level.value)
# ── Step 3: Final decision ────────────────────────────────────────
session.set_decision_type(
DecisionType.APPROVAL if risk_score < 70 else DecisionType.DENIAL
)
session.set_agent_role(AgentRole.PRIMARY)
decision_prompt = (
f"{application_summary} "
f"Classification: {classification}. Risk score: {risk_score}/100."
)
decision_result = await session.run(decision_agent, decision_prompt)
decision_text = decision_result.data
approved = "APPROVE" in decision_text.upper()
return {
"session_id": session.session_id,
"classification": classification,
"risk_score": risk_score,
"approved": approved,
"decision": decision_text,
}
if __name__ == "__main__":
result = asyncio.run(
process_loan_application("A-1042", credit_score=712, income=82000)
)
print(f"Session : {result['session_id']}")
print(f"Class : {result['classification']}")
print(f"Risk : {result['risk_score']}/100")
print(f"Decision : {'APPROVED' if result['approved'] else 'DECLINED'}")
print(f"Reasoning : {result['decision']}")What you’ll see in VeriProof
All three agent runs appear under the same veriproof.session.id:
agent_run pydantic-ai (classify_agent — session.session_id)
agent_run pydantic-ai (risk_agent — same session_id)
agent_run pydantic-ai (decision_agent — same session_id, risk_level=high/medium/low)Each agent_run span carries veriproof.session.id, veriproof.session.intent=advisory, and the governance attributes set at the time of that run.
The three-agent pattern above is a simple sequential pipeline. For branching or parallel execution, use LangGraph to model your graph and the LangGraph instrumentation adapter to capture it.
Adding a human review gate
If your compliance requirements mandate human sign-off before actioning the decision, record the oversight outcome using the session’s fluent setters before the final agent run:
# Signal that human approval is required for this decision
session.set_decision_type(DecisionType.APPROVAL)
session.with_metadata("veriproof.human.oversight", "approval_required")
session.with_metadata("veriproof.human.reviewer_id", "reviewer:R-007")This adds Article 14 (transparency) metadata to the session evidence record in VeriProof’s EU AI Act compliance export.
Next steps
- Post-Decision Outcome Recording guide — link real-world results back to the session
- EU AI Act compliance — Article 9–17 evidence packaging
- LangGraph chatbot example — graph-structured multi-node tracing
- Python SDK Core reference — full
VeriproofSessionand step builder API