ISMS Copilot Docs

Use the API with LangChain

Point LangChain's ChatOpenAI at api.ismscopilot.com/v1, pin framework modules with extra_body, and keep tool-using agents on another model.

LangChain's ChatOpenAI talks to any endpoint that speaks the OpenAI chat completions API. Give it the ISMS Copilot base URL and an sk-isms- key, and your chains get compliance answers with the framework modules you pin.

No tool calling. The API is a text-only subset: it rejects tools with a 400 (see Errors). Do not call bind_tools(), with_structured_output() or create_agent() / AgentExecutor with tools on this model. Keep a general model for the agent loop and use ISMS Copilot as a plain chat step, or wrap a chain that calls it as one of your agent's tools.

Install

pip install langchain-openai
export ISMS_API_KEY=sk-isms-...

First call with a pinned module

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="isms-fast",
    base_url="https://api.ismscopilot.com/v1",
    api_key=os.environ["ISMS_API_KEY"],
    extra_body={"ismscopilot": {"frameworks": ["NIS_2_NL"]}},
)

answer = llm.invoke("We are a managed IT service provider in the Netherlands. Which NIS 2 incident reports do we owe, and to whom?")
print(answer.content)

extra_body adds the ismscopilot extension to every request this model sends. Pinned modules are injected regardless of what the message mentions. Without extra_body, the API uses auto: it detects named frameworks in the user messages and the last assistant turn, not in system messages. Details: Framework knowledge.

To change the pin per call, bind it:

it_llm = llm.bind(extra_body={"ismscopilot": {"frameworks": ["NIS_2_IT", "GDPR"]}})

In a chain

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "You review change requests for a compliance team. Answer in five bullet points."),
    ("user", "{change}"),
])

chain = prompt | llm | StrOutputParser()
print(chain.invoke({"change": "We are moving production logs to a new SaaS provider outside the EU."}))

Your system message is kept and labelled. To drop the ISMS Copilot persona and keep only yours, add "system": "none" to the extension: extra_body={"ismscopilot": {"system": "none", "frameworks": ["GDPR"]}}. See The system prompt, in full.

As a step inside a tool-using agent

The pattern that works: your agent runs on a model with tool calling, and one of its tools calls ISMS Copilot.

from langchain_core.tools import tool

compliance_llm = ChatOpenAI(
    model="isms-thinking",
    base_url="https://api.ismscopilot.com/v1",
    api_key=os.environ["ISMS_API_KEY"],
    extra_body={"ismscopilot": {"frameworks": ["ISO_27001"]}},
)

@tool
def ask_iso27001(question: str) -> str:
    """Answer an ISO 27001:2022 question, citing Annex A control ids."""
    return compliance_llm.invoke(question).content

Give ask_iso27001 to your agent like any other tool. The agent's own model sends the tool definitions; ISMS Copilot only ever receives plain text.

Reading what ran

The response names the injected modules in the x-isms-frameworks header and the ismscopilot body object. ChatOpenAI does not surface custom headers on the message. When you need the disclosure for your audit trail, call the OpenAI SDK directly with with_raw_response (example in Serve customers in many countries).

Limits

  • No tool calling, no JSON mode (response_format other than text), n is 1, no logprobs, no images. Streaming works (llm.stream(...)).
  • Thinking aliases raise max_tokens below 1024 to 1024. Omit max_tokens unless you need a cap.
  • Checked with langchain-openai 0.3.35 on 2026-10-28: the request body carries ismscopilot at the top level, and bind_tools() sends tools, which the API rejects.

On this page