How do I use InjectShield with LangChain?
Two integration points. First, as a BaseCallbackHandler on the LLM chain — intercept every user input and tool output before it reaches the model. Pseudocode:
from langchain.callbacks.base import BaseCallbackHandler
from injectshield import Client
shield = Client(api_key=os.environ["INJECTSHIELD_KEY"])
class InjectShieldCallback(BaseCallbackHandler): def on_chain_start(self, serialized, inputs, **kw): v = shield.classify(inputs.get("input",""), context="user") if v.verdict == "injection": raise PermissionError(v.categories) def on_tool_end(self, output, **kw): v = shield.classify(str(output), context="tool_output") if v.verdict == "injection": raise PermissionError(v.categories) ```
Attach via chain.invoke(..., config={"callbacks":[InjectShieldCallback()]}). Second, as a Runnable in the LCEL graph — RunnableLambda(shield.classify_then_pass) chained ahead of the prompt template. This is preferred for production because it makes the guardrail explicit in the graph and visible in LangSmith traces.
For RAG chains (RetrievalQA, ConversationalRetrievalChain), also scan retrieved documents — wrap the retriever's output via a RunnableLambda that calls shield.classify(doc.page_content, context="document") per chunk and either filters or annotates. For agents (AgentExecutor, OpenAI Functions, ReAct), the callback above already covers tool outputs.
LangSmith traces will show InjectShield verdicts inline; pair with the InjectShield dashboard at injectshield.dev/dashboard for production monitoring. This pattern maps to OWASP LLM01 input + tool-output classification and is documented at injectshield.dev/docs/langchain.