{
  "schema_version": 2,
  "id": "develop/ai/context-engine/lens/agent-integration",
  "title": "Integrate Lens with agent frameworks",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/lens/agent-integration/",
  "summary": "Trace LangGraph, OpenAI Agents SDK, Google ADK, and your own agent loop with Lens, across Agent Memory, Agent Playbooks, and Context Gateway.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-10-26T14:55:43-04:00",
  "page_type": "content",
  "content_hash": "b9dcac577d44fb66632ea791e96febcbe10a49fc01bb8ef5992a1f37b31f3404",
  "sections": [
    {
      "id": "code-examples",
      "title": "Code examples",
      "role": "example",
      "text": "These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.\n\n\nTo trace an agent run in Lens, open a turn around it. Each step the agent takes inside the run, such as a memory recall or a model call, is recorded in that turn. For more about turns and steps, see [Lens concepts](https://redis.io/docs/latest/develop/ai/context-engine/lens/concepts).\n\nBefore you start, get the Lens connection values from the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/lens/quickstart#configure-the-sdk). The framework examples also need a model provider key, such as `OPENAI_API_KEY`."
    },
    {
      "id": "where-the-turn-opens",
      "title": "Where the turn opens",
      "role": "content",
      "text": "| Framework | Open the turn around |\n| --------- | -------------------- |\n| LangGraph | `app.invoke()` or `app.ainvoke()`. With an Iris service attached, `attach()` opens the turn for you. |\n| OpenAI Agents SDK | `Runner.run()` |\n| Google Agent Development Kit (ADK) | `runner.run_async()` |\n| Your own loop | The handler for one message |\n\nTo trace model calls inside the turn, install `redis-iris[llm-tracing]` and call `lens.init()` at startup. See [Trace model calls](https://redis.io/docs/latest/develop/ai/context-engine/lens/instrument#trace-model-calls)."
    },
    {
      "id": "trace-one-turn-across-iris-services",
      "title": "Trace one turn across Iris services",
      "role": "content",
      "text": "When your agent uses Agent Memory, Agent Playbooks, and Context Gateway, a single Lens turn shows how each Iris service contributed to the agent's response. This example needs the connection values for each Iris service.\n\n`workflows.turn()` runs each service's context step before the model and its write-back after. Every service call joins the turn:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\nThe turn shows the memory recall and the Agent Playbooks discovery, then any Context Gateway tool calls your agent makes, and the write-back. In asynchronous code, `workflows.aturn()` runs the services' context steps at the same time. The outer `lens.turn()` sets the outcome. When a turn is already open, `workflows.turn()` and `attach()` add their steps to it rather than starting another."
    },
    {
      "id": "langgraph",
      "title": "LangGraph",
      "role": "content",
      "text": "Install LangGraph and the LangChain OpenAI integration:\n\n[code example]\n\nWrap the graph run in `lens.turn()`. LangGraph's thread ID identifies the conversation, so pass it as the Lens session ID:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\nEach model call in the graph joins the turn with its token counts."
    },
    {
      "id": "attach-an-iris-service",
      "title": "Attach an Iris service",
      "role": "content",
      "text": "When the graph uses Agent Memory or Agent Playbooks, `attach()` adds the service's context before your first node and its write-back after your last. With Lens on, every run of an attached graph is one turn. The session comes from `thread_id` and the user from `user_id` in the run's configuration:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\n`attach()` needs the `langgraph` extra: `python -m pip install 'redis-iris[langgraph]'`."
    },
    {
      "id": "openai-agents-sdk",
      "title": "OpenAI Agents SDK",
      "role": "content",
      "text": "Install the OpenAI Agents SDK:\n\n[code example]\n\nWrap `Runner.run()` in `lens.turn()`:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\nThe OpenAI Agents SDK calls models through the OpenAI client, so each model call joins the turn with its token counts."
    },
    {
      "id": "google-adk",
      "title": "Google ADK",
      "role": "content",
      "text": "Install the Google ADK:\n\n[code example]\n\nWrap the `runner.run_async()` loop in `lens.turn()`:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\nThe turn records the agent run, its outcome, and every Iris service call the agent makes. The example uses a Gemini model and needs `GOOGLE_API_KEY`."
    },
    {
      "id": "your-own-agent-loop",
      "title": "Your own agent loop",
      "role": "content",
      "text": "Wrap the handler for one message in `lens.turn()`, and set the outcome on each path:\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\nEach call to `handle()` records one turn under the session and user IDs you pass. The turn is marked `completed` when the model answers, or `failed` when the call raises. Record your retrievals and prompt assembly inside the same turn to see which context reached the model."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "- [Instrument an agent](https://redis.io/docs/latest/develop/ai/context-engine/lens/instrument): record retrievals, memory recalls, prompt assembly, and custom steps.\n- [Inspect sessions](https://redis.io/docs/latest/develop/ai/context-engine/lens/inspect-sessions): read the turns you traced in the Lens user interface (UI).\n- [Query sessions and turns](https://redis.io/docs/latest/develop/ai/context-engine/lens/read-api): read turns from code."
    }
  ],
  "examples": [
    {
      "id": "trace-one-turn-across-iris-services-ex0",
      "language": "python",
      "code": "from redis_iris import Iris, lens, workflows\nfrom redis_iris.hooks import stack\n\nlens.init(agent_id=\"support-bot\")\n\niris = Iris.from_env()\nmemory = iris.agent_memory(assistant_id=\"support-bot\")\nplaybook = iris.agent_playbooks()\ngateway = iris.context_gateway()\n\nhooks = stack(memory.hooks(), playbook.disclosure(audience=\"support\"))\n\n\ndef run_agent(context, message, tools):\n    # Your model and tool loop goes here. It receives the Iris context and tools.\n    return \"Your refund was issued on May 2.\"\n\n\ndef handle(owner, message, thread_id):\n    with lens.turn(thread_id, user_id=owner) as outer:\n        with workflows.turn(hooks, message, owner=owner, session=thread_id) as turn:\n            tools = [*gateway.model_tools(), *hooks.tools()]\n            answer = run_agent(turn.context, message, tools)\n            turn.record(answer)\n        outer.set_outcome(\"completed\")\n    return answer\n\n\nprint(handle(\"user-1042\", \"Where can I see my refund status?\", \"thread-1\"))",
      "section_id": "trace-one-turn-across-iris-services"
    },
    {
      "id": "langgraph-ex0",
      "language": "bash",
      "code": "python -m pip install 'redis-iris[llm-tracing]' langgraph langchain-openai",
      "section_id": "langgraph"
    },
    {
      "id": "langgraph-ex1",
      "language": "python",
      "code": "from langchain_openai import ChatOpenAI\nfrom langgraph.graph import END, START, MessagesState, StateGraph\n\nfrom redis_iris import lens\n\nlens.init(agent_id=\"support-bot\")\nmodel = ChatOpenAI(model=\"gpt-4o-mini\")\n\n\ndef assistant(state: MessagesState):\n    return {\"messages\": [model.invoke(state[\"messages\"])]}\n\n\ngraph = StateGraph(MessagesState)\ngraph.add_node(\"assistant\", assistant)\ngraph.add_edge(START, \"assistant\")\ngraph.add_edge(\"assistant\", END)\napp = graph.compile()\n\nthread_id = \"thread-1\"\nwith lens.turn(thread_id, user_id=\"user-1042\") as turn:\n    result = app.invoke(\n        {\"messages\": [(\"user\", \"Where can I see my refund status?\")]},\n        {\"configurable\": {\"thread_id\": thread_id}},\n    )\n    turn.set_outcome(\"completed\")\n\nprint(result[\"messages\"][-1].content)",
      "section_id": "langgraph"
    },
    {
      "id": "attach-an-iris-service-ex0",
      "language": "python",
      "code": "from redis_iris import AgentMemory\nfrom redis_iris.integrations.langgraph import attach\n\nmemory = AgentMemory.from_env()\napp = attach(memory, graph).compile()\n\nresult = app.invoke(\n    {\"messages\": [(\"user\", \"Where can I see my refund status?\")]},\n    {\"configurable\": {\"user_id\": \"user-1042\", \"thread_id\": \"thread-1\"}},\n)",
      "section_id": "attach-an-iris-service"
    },
    {
      "id": "openai-agents-sdk-ex0",
      "language": "bash",
      "code": "python -m pip install 'redis-iris[llm-tracing]' openai-agents",
      "section_id": "openai-agents-sdk"
    },
    {
      "id": "openai-agents-sdk-ex1",
      "language": "python",
      "code": "import asyncio\n\nfrom agents import Agent, Runner\n\nfrom redis_iris import lens\n\nlens.init(agent_id=\"support-bot\")\nagent = Agent(name=\"Support\", instructions=\"Answer refund questions in two sentences.\")\n\n\nasync def handle(session_id, user_id, message):\n    with lens.turn(session_id, user_id=user_id) as turn:\n        result = await Runner.run(agent, message)\n        turn.set_outcome(\"completed\")\n    return result.final_output\n\n\nprint(asyncio.run(handle(\"session-1\", \"user-1042\", \"Where can I see my refund status?\")))",
      "section_id": "openai-agents-sdk"
    },
    {
      "id": "google-adk-ex0",
      "language": "bash",
      "code": "python -m pip install redis-iris google-adk",
      "section_id": "google-adk"
    },
    {
      "id": "google-adk-ex1",
      "language": "python",
      "code": "import asyncio\n\nfrom google.adk.agents import Agent\nfrom google.adk.runners import InMemoryRunner\nfrom google.genai import types\n\nfrom redis_iris import lens\n\nlens.init(agent_id=\"support-bot\")\nagent = Agent(\n    name=\"support\",\n    model=\"gemini-2.0-flash\",\n    instruction=\"Answer refund questions in two sentences.\",\n)\nrunner = InMemoryRunner(agent, app_name=\"support\")\n\n\nasync def handle(session_id, user_id, message):\n    await runner.session_service.create_session(\n        app_name=\"support\", user_id=user_id, session_id=session_id\n    )\n    content = types.Content(role=\"user\", parts=[types.Part(text=message)])\n    answer = \"\"\n    with lens.turn(session_id, user_id=user_id) as turn:\n        async for event in runner.run_async(\n            user_id=user_id, session_id=session_id, new_message=content\n        ):\n            if event.is_final_response() and event.content:\n                answer = event.content.parts[0].text\n        turn.set_outcome(\"completed\")\n    return answer\n\n\nprint(asyncio.run(handle(\"session-1\", \"user-1042\", \"Where can I see my refund status?\")))",
      "section_id": "google-adk"
    },
    {
      "id": "your-own-agent-loop-ex0",
      "language": "python",
      "code": "from redis_iris import lens\n\n\ndef call_model(message, context):\n    # Your model call goes here.\n    return \"Your refund was issued on May 2.\"\n\n\ndef handle(session_id, user_id, message):\n    with lens.turn(session_id, user_id=user_id) as turn:\n        try:\n            answer = call_model(message, context=[])\n        except Exception:\n            turn.set_outcome(\"failed\")\n            raise\n        turn.set_outcome(\"completed\")\n    return answer\n\n\nprint(handle(\"session-1\", \"user-1042\", \"Where can I see my refund status?\"))",
      "section_id": "your-own-agent-loop"
    }
  ]
}
