Skip to main content

TypeSafe integrations

还没翻译译自英文(docs.langchain.com)本页 36 段都还没译

Jev is a System One model that reads natural language but returns typed answers and calibrated probabilities instead of generated text.

TypeSafeClassifier exposes these decisions as a LangChain Runnable, so you can invoke, batch, or compose them with other runnables. It accepts strings, structured JSON, and LangChain message objects, and records traces and token usage in LangSmith. Use it for focused decisions such as routing a request, choosing a model, or checking whether a tool call is safe to run.

Use TypeSafe decisions in LangChain middleware to control create_agent behavior at specific lifecycle points, including with custom middleware that classifies agent state. See Agent middleware for examples.

Setup

uv add langchain-typesafe
pip install langchain-typesafe

Create an API key in the TypeSafe console and export it:

export TYPESAFE_API_KEY=...

Note

Optional: Set TYPESAFE_BASE_URL to use a compatible gateway, test server, or private deployment. The default is https://api.typesafe.ai.

export TYPESAFE_BASE_URL=https://gateway.example.com

Quickstart

Create a TypeSafeClassifier, then pass the state and named questions together in each invocation. Questions that share state are evaluated independently and in parallel in one request:

Note

Earlier versions configured questions on TypeSafeClassifier and passed only the state to invoke. Pass both state and questions to invoke now.

from langchain_typesafe import Choice, Noul, Score, TypeSafeClassifier

classifier = TypeSafeClassifier()

response = classifier.invoke(
    {
        "state": (
            "The deploy failed twice and customers are seeing 500s. "
            "Can someone look now?"
        ),
        "questions": {
            "urgent": Noul(instructions="Does this need attention right now?"),
            "team": Choice(
                instructions="Which team should pick this up?",
                criteria={
                    "infra": "Deploys, availability, and on-call incidents.",
                    "billing": "Payments, invoices, and subscriptions.",
                },
            ),
            "severity": Score(
                instructions="How severe is the impact?",
                criteria=["Cosmetic.", "Degraded for some users.", "Full outage."],
            ),
        },
    }
)

print(response.nouls["urgent"].noul)
print(response.choices["team"].choice, response.choices["team"].confidence)
print(response.scores["severity"].score)

Answers are keyed by the question IDs you supplied, and grouped by type on nouls, choices, and scores. The response also carries the model that answered, token usage, and the TypeSafe request_id.

The request state can be a string, a JSON object or array, or LangChain messages. A BaseMessage or a sequence of messages is converted to role/content JSON, including when nested inside a larger object.

Decision types

Each question is one of three primitives:

PrimitiveAsksReturnsReach for it when
NoulIs this true?noul, the probability of yesYour code branches on an if
ChoiceWhich of these options?choice, plus probabilities and confidenceOptions map to distinct code paths
ScoreWhich level?score, plus legend, probabilities, and confidenceThe answer is a spectrum you compare to a threshold

Noul is the only one without a confidence, since the probability is the answer. Use Score rather than a Noul for a spectrum: a Noul of 0.5 means an even split between yes and no, not "medium".

Agent middleware

The package includes two experimental middleware that put the classifier on an agent's decision points. Import them from langchain_typesafe.experimental.middleware.

Note

The middleware are experimental and require langchain-typesafe[experimental]. Their APIs may change without notice.

The examples below use OpenAI models. Install the experimental extra and the OpenAI integration before using them:

uv add "langchain-typesafe[experimental]" langchain-openai
pip install "langchain-typesafe[experimental]" langchain-openai
MiddlewareHookDecision
ModelRouterMiddlewarebefore_agent, wrap_model_callWhich model handles the run
AutoModeMiddlewarewrap_tool_callWhether a tool call is too risky to run

Model routing

Classifies the latest human message across your named models and uses the selected one for every model call in the run. Each ModelChoice pairs a model with the criterion for picking it:

from langchain.agents import create_agent
from langchain_typesafe.experimental.middleware import (
    ModelChoice,
    ModelRouterMiddleware,
)

router = ModelRouterMiddleware(
    choices={
        "fast": ModelChoice(
            model="openai:gpt-5.6-terra",
            criteria="Direct lookups, extraction, and localized changes with explicit targets.",
        ),
        "powerful": ModelChoice(
            model="openai:gpt-6-astra",
            criteria="Architecture, novel root-cause reasoning, and high-stakes decisions.",
        ),
    },
    instructions="Choose the least costly model that can complete the task safely.",
)

agent = create_agent("openai:gpt-5.6-terra", middleware=[router])

result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "Prove that there are infinitely many prime numbers.",
            }
        ]
    }
)
print(result["model_route"].choice)

Tool-risk gating

Asks for the probability that a tool call is risky or insufficiently authorized. Calls that are determined risky return an error ToolMessage instead of running the tool. Only the tools you list are classified. Pass their names or tool objects:

from langchain.agents import create_agent
from langchain.messages import ToolMessage
from langchain.tools import tool
from langchain_typesafe import NoulCriteria
from langchain_typesafe.experimental.middleware import AutoModeMiddleware


@tool
def delete_all_backups() -> str:
    """Delete every backup. This action cannot be undone."""
    return "Backups deleted."


agent = create_agent(
    "openai:gpt-6-astra",
    tools=[delete_all_backups],
    middleware=[AutoModeMiddleware(tools=[delete_all_backups])],
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "Delete all backups."}]}
)
print(result["messages"][-1].content)

Override instructions, or pass criteria=NoulCriteria(true=..., false=...), to describe risk for your own tools.

Warning

Do not put secrets in tool arguments or conversation state unless sending them to TypeSafe is acceptable. This middleware refuses risky calls. It does not request approval. Pair it with human-in-the-loop middleware when you want a person to approve them.

Custom middleware

TypeSafeClassifier accepts LangChain message objects directly, so a custom middleware hook can classify an agent's conversation state without converting it first. This example classifies the conversation once at the start of each run and stores the complete ChoiceAnswer in agent state:

from langchain.agents import create_agent
from langchain.agents.middleware import AgentMiddleware, AgentState, Runtime
from langchain_typesafe import Choice, ChoiceAnswer, TypeSafeClassifier
from typing_extensions import NotRequired


class TriageState(AgentState):
    triage: NotRequired[ChoiceAnswer]


class TriageMiddleware(AgentMiddleware[TriageState]):
    state_schema = TriageState

    def __init__(self) -> None:
        self.classifier = TypeSafeClassifier()

    def before_agent(
        self, state: TriageState, runtime: Runtime
    ) -> dict[str, ChoiceAnswer]:
        response = self.classifier.invoke(
            {
                "state": state["messages"],
                "questions": {
                    "triage": Choice(
                        instructions="Which team should handle this conversation?",
                        criteria={
                            "billing": "Payments, invoices, and subscriptions.",
                            "infra": "Deploys, availability, and incidents.",
                            "other": "Requests that belong to another team.",
                        },
                    )
                },
            }
        )
        return {"triage": response.choices["triage"]}


agent = create_agent(
    "openai:gpt-5.6-terra",
    middleware=[TriageMiddleware()],
)
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Customers are seeing 500 errors."}]}
)
print(result["triage"].choice, result["triage"].confidence)

Use any lifecycle hook that matches your decision point. For example, use before_model to reclassify after each tool result, or wrap_tool_call to classify a proposed action. See Custom middleware for all hooks and state patterns.

Tracing

TypeSafe classifications are traced in LangSmith, so you can inspect decisions, token usage, and spend alongside the rest of your agent.

See also